clase 13 seguridad

64
Seguridad Realizada por: Christian Aquino |@cj_aquino Diego Ramirez |@thedarsideofit Gonzalo Alonso |@GonzaloAlonsoD Diego Barros |@Inmzombie Para: Hydras C&S |@hydras_cs Basada en Libro Symfony 2 en español Nacho Pacheco y The Book

Upload: hydrascs

Post on 19-Jun-2015

240 views

Category:

Documents


0 download

DESCRIPTION

www.hydrascs.com

TRANSCRIPT

Page 1: Clase 13   seguridad

Seguridad

Realizada por:Christian Aquino |@cj_aquinoDiego Ramirez |@thedarsideofitGonzalo Alonso |@GonzaloAlonsoDDiego Barros |@Inmzombie

Para: Hydras C&S |@hydras_csBasada en Libro Symfony 2 en español Nacho Pacheco y The Book

Page 2: Clase 13   seguridad

Seguridad etapas

Page 3: Clase 13   seguridad

Autenticación HTTP

security: firewalls: secured_area: pattern: ^/ anonymous: ~ http_basic: realm: "Secured Demo Area"

access_control: - { path: ^/admin, roles: ROLE_ADMIN }

Page 4: Clase 13   seguridad

Autenticación HTTP

providers: in_memory: memory: users: ryan: { password: ryanpass, roles: 'ROLE_USER' } admin: { password: kitten, roles: 'ROLE_ADMIN' }

encoders: Symfony\Component\Security\Core\User\User: plaintext

Page 5: Clase 13   seguridad

Autenticación HTTP● Hay dos usuarios en el sistema (ryan y admin);● Los usuarios se autentican a través de la autenticación

HTTP básica del sistema;● Cualquier URL que coincida con /admin/* está

protegida, y sólo el usuario admin puede acceder a ellas;

● Todas las URL que no coincidan con /admin/* son accesibles para todos los usuarios (y nunca se pide al usuario que se registre).

Page 6: Clase 13   seguridad

Cortafuegos (Autenticación)

Page 7: Clase 13   seguridad

Cortafuegos (Autenticación)El trabajo del cortafuegos es determinar si el usuario necesita estar autenticado, y si lo hace, enviar una respuesta al usuario para iniciar el proceso de autenticación.En este ejemplo el patrón (^/) concordará con cada petición entrante.Cualquier usuario puede acceder a /foo sin que se le pida se autentique.Puesto que no hay rol especial necesario para acceder a /foo (bajo la sección access_control), la petición se puede llevar a cabo sin solicitar al usuario se autentiqueSi eliminas la clave anonymous, el cortafuegos siempre hará que un usuario se autentique inmediatamente.

Page 8: Clase 13   seguridad

Control de acceso (Autorización)

Page 9: Clase 13   seguridad

Control de acceso (Autorización)

Si un usuario solicita /admin/foo, la configuración access_control dice que cualquier URL coincidente con el patrón de la expresión regular ^/admin (/admin o /admin/*) requiere el rol ROLE_ADMIN.Los roles son la base para la mayor parte de la autorización: solo puede acceder a /admin/foo si cuenta con el rol ROLE_ADMIN.

Page 10: Clase 13   seguridad

Control de acceso (Autorización)

Page 11: Clase 13   seguridad

Control de acceso (Autorización)

El usuario ryan se autentica correctamente con el cortafuegos. Pero como ryan no cuenta con el rol ROLE_ADMIN, se le sigue negando el acceso a /admin/foo. En última instancia, el usuario debe ver algún tipo de mensaje indicándole que se le ha denegado el acceso.Cuando Symfony niega el acceso al usuario, él verá una pantalla de error y recibe un código de estado HTTP 403 (Prohibido).

Page 12: Clase 13   seguridad

Control de acceso (Autorización)

Page 13: Clase 13   seguridad

Control de acceso (Autorización)Si admin solicita /admin/foo, después de haberse autenticado, la capa de control de acceso le permitirá pasar a través de la petición.El flujo de la petición cuando un usuario solicita un recurso protegido es sencillo. Independientemente del método de autenticación, siempre es el mismo:1. Un usuario accede a un recurso protegido2. Se redirige al usuario al formulario de acceso3. El usuario presenta sus credenciales

(usuario/contraseña)4. El cortafuegos autentica al usuario5. El nuevo usuario autenticado intenta de nuevo la

petición original.

Page 14: Clase 13   seguridad

Usando un formulario de acceso tradicional

activa el formulario de acceso en el cortafuegos:

# app/config/security.ymlsecurity: firewalls: secured_area: pattern: ^/ anonymous: ~ form_login: login_path: login check_path: login_check

Page 15: Clase 13   seguridad

Usando un formulario de acceso tradicional

Si no necesitas personalizar tus valores login_path o check_path (los valores utilizados aquí son los valores predeterminados), puedes acortar tu configuración:

form_login: ~

Page 16: Clase 13   seguridad

Configurar rutas

# app/config/routing.ymllogin: pattern: /login defaults: { _controller: AcmeSecurityBundle:Security:login }login_check: pattern: /login_check

Page 17: Clase 13   seguridad

Controlador// src/Acme/SecurityBundle/Controller/SecurityController.php;namespace Acme\SecurityBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\Security\Core\SecurityContext;

class SecurityController extends Controller{ public function loginAction() { $request = $this->getRequest(); $session = $request->getSession();

Page 18: Clase 13   seguridad

Controlador // obtiene el error de inicio de sesión si lo hay if ($request->attributes->has(

SecurityContext::AUTHENTICATION_ERROR)) { $error = $request->attributes->get( SecurityContext::AUTHENTICATION_ERROR ); } else { $error = $session->get(

SecurityContext::AUTHENTICATION_ERROR); $session->remove(

SecurityContext::AUTHENTICATION_ERROR);

Page 19: Clase 13   seguridad

Controlador }

return $this->render( 'AcmeSecurityBundle:Security:login.html.twig', array( // último nombre de usuario ingresado 'last_username' => $session->get(

SecurityContext::LAST_USERNAME), 'error' => $error, ) ); }}

Page 20: Clase 13   seguridad

Controlador

El trabajo es mostrar el formulario al usuario y los errores de ingreso que puedan haber ocurrido, el propio sistema de seguridad se encarga de verificar el nombre de usuario y contraseña y la autenticación del usuario.

Page 21: Clase 13   seguridad

Plantilla{% if error %} <div>{{ error.message }}</div>{% endif %}<form action="{{ path('login_check') }}" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="{{ last_username }}" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <button type="submit">login</button></form>

Page 22: Clase 13   seguridad

PlantillaRequisitos:Presentando el formulario a /login_check (a través de la ruta login_check), el sistema de seguridad debe interceptar el envío del formulario y procesarlo automáticamente.El sistema de seguridad espera que los campos presentados se llamen _username y _password.Proceso:1. Intenta acceder2. El cortafuegos inicia la autenticación (/login)3. /login reproduce el formulario4. El usuario envía el formulario de acceso a /login_check5. El sistema de seguridad intercepta la petición, comprueba

las credenciales, autentica al usuario si todo está correcto, y si no, envía al usuario de nuevo al formulario de acceso.

Page 23: Clase 13   seguridad

Evitando errores comunes1. Crea las rutas correctas

2. Asegúrate de que la página de inicio de sesión no esté protegida

3. Asegúrate de que /login_check está detrás de un cortafuegos

4. Múltiples cortafuegos no comparten el contexto de seguridad

Page 24: Clase 13   seguridad

Autorizando

Una vez que el usuario se ha autenticado, comienza la autorización. La autorización proporciona una forma estándar y potente para decidir si un usuario puede acceder a algún recurso (una URL, un modelo de objetos, una llamada a un método, ...). Esto funciona asignando roles específicos a cada usuario y, a continuación, requiriendo diferentes roles para diferentes recursos.

Page 25: Clase 13   seguridad

Protegiendo patrones de URL

# app/config/security.ymlsecurity: # ... access_control: - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN } - { path: ^/admin, roles: ROLE_ADMIN }

^/admin/users/admin/users/users/admin

Page 26: Clase 13   seguridad

Entendiendo como trabaja access_control

Cada access_control tiene varias opciones que configuran dos diferentes cosas: (a) la petición entrante emparejada debe tener esta entrada de control de acceso y (b) una vez emparejada, debe tener algún tipo de restricción de acceso aplicable:

# app/config/security.ymlsecurity: # ... access_control: - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN } - { path: ^/admin, roles: ROLE_ADMIN }

Page 27: Clase 13   seguridad

Emparejando opciones

Symfony2 crea una instancia de Symfony\Component\HttpFoundation\RequestMatcher para cada entrada access_control.

Las siguientes opciones de access_control se utilizan para emparejar:

● path● ip● host● methods

Page 28: Clase 13   seguridad

Emparejando opciones# app/config/security.ymlsecurity: # ... access_control: - { path: ^/admin, roles: ROLE_USER_IP, ip: 127.0.0.1 } - { path: ^/admin, roles: ROLE_USER_HOST, host: symfony.com } - { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] } - { path: ^/admin, roles: ROLE_USER }

Page 29: Clase 13   seguridad

1. { path: ^/admin, roles: ROLE_USER_IP, ip: 127.0.0.1 }2. { path: ^/admin, roles: ROLE_USER_HOST, host: symfony.com }3. { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] }4. { path: ^/admin, roles: ROLE_USER }

Page 30: Clase 13   seguridad

1. { path: ^/admin, roles: ROLE_USER_IP, ip: 127.0.0.1 }2. { path: ^/admin, roles: ROLE_USER_HOST, host: symfony.com }3. { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] }4. { path: ^/admin, roles: ROLE_USER }

Page 31: Clase 13   seguridad

1. { path: ^/admin, roles: ROLE_USER_IP, ip: 127.0.0.1 }2. { path: ^/admin, roles: ROLE_USER_HOST, host: symfony.com }3. { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] }4. { path: ^/admin, roles: ROLE_USER }

Page 32: Clase 13   seguridad

Forzando el accesoAl decidir que entrada access_control concuerda (si la hay), aplica las restricciones de acceso basándose en las opciones roles y requires_channel:● role Si el usuario no tiene determinado rol o roles, entonces

el acceso es denegado (internamente, se lanza una Symfony\Component\Security\Core\Exception\AccessDeniedException);

● requires_channel Si el canal de la petición entrante (p. ej. http) no concuerda con este valor (p. ej. https), el usuario será redirigido (p. ej. redirigido de http a https, o viceversa).

Si el acceso es denegado, el sistema intentará autenticar al usuario si aún no lo está. Si el usuario ya inició sesión, se mostrará la página del error 403 «acceso denegado».

Page 33: Clase 13   seguridad

Protegiendo por IP

# app/config/security.ymlsecurity: # ... access_control:

- { path: ^/esi, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }

- { path: ^/esi, roles: ROLE_NO_ACCESS }

Page 34: Clase 13   seguridad

Protegiendo por canal

# app/config/security.ymlsecurity: # ... access_control: - {

path: ^/cart/checkout,roles: IS_AUTHENTICATED_ANONYMOUSLY,requires_channel: https

}

Page 35: Clase 13   seguridad

Protegiendo un controlador

// ...use Symfony\Component\Security\Core\Exception\AccessDeniedException;

public function helloAction($name){ if (false === $this->get('security.context')

->isGranted('ROLE_ADMIN')) {

throw new AccessDeniedException(); } // ...}

Page 36: Clase 13   seguridad

Protegiendo un controlador usando anotaciones

// ...use JMS\SecurityExtraBundle\Annotation\Secure;

/** * @Secure(roles="ROLE_ADMIN") */public function helloAction($name){ // ...}

Page 37: Clase 13   seguridad

Usuarios

De donde provienen los usuarios? (Proveedores de usuarios)El usuario envía un conjunto de credenciales (username y password). El trabajo del sistema de autenticación es concordar esas credenciales contra una piscina de usuarios.Los usuarios pueden venir de cualquier parte. Todo lo que proporcione usuarios a la autenticación se llama «proveedor de usuario».Proveedores de usuario más comunes:Carga usuarios de un archivo de configuración.Carga usuarios de una tabla de la base de datos.

Page 38: Clase 13   seguridad

Especificando usuarios en un archivo de configuración (en memoria)

# app/config/security.ymlsecurity: # ... providers: default_provider: memory: users: ryan: {

password: ryanpass, roles: 'ROLE_USER' } admin: {

password: kitten, roles: 'ROLE_ADMIN' }

Page 39: Clase 13   seguridad

Especificando usuarios en un archivo de configuración (en memoria)

prudencia nombre de usuario utilizar la sintaxis alterna

users: - { name: 77, password: pass, roles: 'ROLE_USER' } - { name: user-name, password: pass, roles: 'ROLE_USER' }

Page 40: Clase 13   seguridad

Cargando usuarios de la base de datos

Si deseas cargar tus usuarios a través del ORM de Doctrine, lo puedes hacer creando una clase User y configurando el proveedor entity.

Page 41: Clase 13   seguridad

Restringiendo el acceso# app/config/security.ymlsecurity:

firewalls:frontend:

pattern: ^/*anonymous: ~form_login: ~

access_control:- { path: ^/usuario/login, roles:IS_AUTHENTICATED_ANONYMOUSLY }

Page 42: Clase 13   seguridad

Restringiendo el acceso- { path: ^/usuario/registro, roles:IS_AUTHENTICATED_ANONYMOUSLY }- { path: ^/usuario/*, roles: ROLE_USUARIO }

providers:usuarios:

entity: {class: Clase\UsuarioBundle\Entity\Usuario,property: email }

encoders:Clase\UsuarioBundle\Entity\Usuario: {algorithm: sha512, iterations: 10 }

Page 43: Clase 13   seguridad

Creando la entidad usuario$ php app/console doctrine:generate:entityThe Entity shortcut name: UsuarioBundle:UsuarioConfiguration format (yml, xml, php, or annotation) [annotation]:

New field name (): nombreField type [string]: <Enter>

New field name (): apellidosField type [string]: <Enter>

New field name (): emailField type [string]: <Enter>

Page 44: Clase 13   seguridad

New field name (): passwordField type [string]: <Enter>

New field name (): saltField type [string]: <Enter>

New field name (): <Enter>Do you want to generate an empty repository class [no]? noDo you confirm generation [yes]? yes

Page 45: Clase 13   seguridad

Creando el proveedor de usuarios// src/Clase/UsuarioBundle/Entity/Usuario.phpnamespace Clase\UsuarioBundle\Entity;use Symfony\Component\Security\Core\User\UserInterface;use Doctrine\ORM\Mapping as ORM;/*** Cupon\UsuarioBundle\Entity\Usuario** @ORM\Entity*/class Usuario implements UserInterface{...}

Page 46: Clase 13   seguridad

// src/Clase/UsuarioBundle/Entity/Usuario.phpclass Usuario implements UserInterface{function eraseCredentials() {}function getRoles(){return array('ROLE_USUARIO');}function getUsername(){return $this->getEmail();}// ...}

Page 47: Clase 13   seguridad

Implementar UserInterface

• eraseCredentials(), se invoca cuando la aplicación necesita borrar la información más sensible del usuario, como por ejemplo su contraseña.• getPassword(), se invoca cada vez que la aplicación necesita obtener la contraseña del usuario.• getRoles(), cuando se autentica a un usuario, se invoca este método para obtener un array con todos los roles que posee.• getSalt(), devuelve el valor que se utilizó para aleatorizar la contraseña cuando se creó el usuario.• getUsername(), se invoca para obtener el login o nombre de usuario que se utiliza para autenticar a los usuarios.

Page 48: Clase 13   seguridad

Añadiendo el formulario de login

usuario_login:pattern: /usuario/logindefaults: { _controller: UsuarioBundle:Default:login }

usuario_login_check:pattern: /usuario/login_check

usuario_logout:pattern: /usuario/logout

Page 49: Clase 13   seguridad

Añadiendo el formulario de login

• /login, se utiliza para mostrar el formulario de login.

• /login_check, es la acción que comprueba que el usuario y contraseña introducidos son correctos.

• /logout, se emplea para desconectar al usuario logueado.

Page 50: Clase 13   seguridad

Actualizar ruta form_login# app/config/security.ymlsecurity:

firewalls:frontend:

pattern: ^/*anonymous: ~form_login:

login_path: /usuario/logincheck_path: /usuario/login_checklogin_path: usuario_logincheck_path: usuario_login_check

Page 51: Clase 13   seguridad

El controlador//src/Clase/UsuarioBundle/Controller/DefaultController.phpnamespace Clase\UsuarioBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\Security\Core\SecurityContext;class DefaultController extends Controller{public function loginAction(){

$peticion = $this->getRequest();$sesion = $peticion->getSession();$error = $peticion->attributes->get(

Page 52: Clase 13   seguridad

El controladorSecurityContext::AUTHENTICATION_ERROR,$sesion->get(SecurityContext::AUTHENTICATION_ERROR)

);return $this->render('UsuarioBundle:Default:login.html.twig', array(

'last_username' => $sesion->get(SecurityContext::LAST_USERNAME),'error' => $error

));}}

Page 53: Clase 13   seguridad

La vista del formulario{# src/Clase/UsuarioBundle/Resources/views/Default/login.html.twig #}{% if error %}

<div>{{ error.message }}</div>{% endif %}<form action="{{ path('usuario_login_check') }}" method="post">

<label for="username">Usuario:</label><input type="text" id="username" name="_username"value="{{ last_username }}" /><label for="password">Contraseña:</label><input type="password" id="password" name="_password" /><input type="submit" name="login" value="Acceder" />

</form>

Page 54: Clase 13   seguridad

Formulario de registro

#routing.yml

usuario_registro:pattern: /registrodefaults: { _controller: UsuarioBundle:Default:registro }

Page 55: Clase 13   seguridad

Controlador registro

// src/Clase/UsuarioBundle/Controller/DefaultController.phpnamespace Clase\UsuarioBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Clase\UsuarioBundle\Entity\Usuario;use Clase\UsuarioBundle\Form\Frontend\UsuarioType;

class DefaultController extends Controller{// ...

Page 56: Clase 13   seguridad

Controlador registropublic function registroAction(){

$usuario = new Usuario();$formulario = $this->createForm(new UsuarioType(), $usuario);return $this->render(

'UsuarioBundle:Default:registro.html.twig',array('formulario' => $formulario->createView())

);}}

Page 57: Clase 13   seguridad

Plantilla registro

{# src/Clase/UsuarioBundle/Resources/views/Default/registro.html.twig #}

<form action="{{ path('usuario_registro') }}" method="post"{{ form_enctype(formulario) }}>

{{ form_widget(formulario) }}<input class="boton" type="submit"

value="Registrarme" /></form>

Page 58: Clase 13   seguridad

Formulario registro

// src/Clase/UsuarioBundle/Form/Frontend/UsuarioType.phpnamespace Clase\UsuarioBundle\Form\Frontend;use Symfony\Component\Form\AbstractType;use Symfony\Component\Form\FormBuilderInterface;use Symfony\Component\OptionsResolver\OptionsResolverInterface;class UsuarioType extends AbstractType{

public function buildForm(FormBuilderInterface $builder, array $options){

Page 59: Clase 13   seguridad

$builder->add('nombre')->add('apellidos')->add('email', 'email')->add('password', 'repeated', array(

'type' => 'password','invalid_message' => 'Las dos contraseñas deben coincidir','options' => array('label' => 'Contraseña')

));

}

Page 60: Clase 13   seguridad

public function setDefaultOptions(OptionsResolverInterface $resolver){

$resolver->setDefaults(array('data_class' =>'Clase\UsuarioBundle\Entity\Usuario'

));}public function getName(){

return 'clase_usuariobundle_usuariotype';}

}

Page 61: Clase 13   seguridad

Controlador registro procesar formpublic function registroAction(){

$peticion = $this->getRequest();$usuario = new Usuario();$formulario = $this->createForm(new UsuarioType(), $usuario);if ($peticion->getMethod() == 'POST') {

$formulario->bind($peticion);if ($formulario->isValid()) {

$encoder = $this->get('security.encoder_factory')->getEncoder($usuario);

Page 62: Clase 13   seguridad

$usuario->setSalt(md5(time()));$passwordCodificado =

$encoder->encodePassword($usuario->getPassword(),$usuario->getSalt()

);$usuario->setPassword($passwordCodificado);

$em = $this->getDoctrine()->getEntityManager();$em->persist($usuario);$em->flush();

Page 63: Clase 13   seguridad

$token = new UsernamePasswordToken($usuario,$usuario->getPassword(),'usuarios',$usuario->getRoles()

);$this->container

->get('security.context')->setToken($token);

return $this->redirect($this->generateUrl('url'));}

Page 64: Clase 13   seguridad

}

return $this->render('UsuarioBundle:Default:registro.html.twig',array('formulario' => $formulario->createView())

);}}