Revision 329727 of Consideraciones de Seguridad

  • Revision slug: Persona/Security_Considerations
  • Revision title: Consideraciones de Seguridad
  • Revision id: 329727
  • Created:
  • Creator: ccarruitero
  • Is current revision? No
  • Comment
Tags: 

Revision Content

Cuando agregas a tu sitio web soporte para Persona, Persona toma tantas medidas de seguridad como puede. Sin embargo, algunas medidas de seguridad solo pueden ser manejados por tu sitio web. Estas son listadas a continuación.

Prácticas Esenciales

Verificar la confirmación en tu servidor

Cuando utilizas Persona, las declaraciones de identidad son pasada dentro de la función onlogin a través de

{{ domxref("navigator.id.watch()") }}

Siempre debes pasar la declaración a tu servidor para verificarla, y solo tu servidor debe decidir si autorizar al usuario permisos adicionales en base al resultado de la verificación:

// Inside navigator.id.watch({ ...
onlogin: function(assertion) {
  // A user wants to log in! Here you need to:
  // 1. Send the assertion to your backend for verification and to create a session.
  // 2. Update your UI.
},

Si trata de verifcar la declaración usando JavaScript ejecutandose en el navegador del usuario, algún usuario malicioso podría suplantar por otro usuario legítimo de su sitio inyectando código bloqueando tu código JavaScript. Esto es posible debido a que no se tiene control del navegador del usuario, donde se ejecuta el código.

Como mencionamos lineas arriba, siempre debe pasar la declaración a su servidor para la verificación. Incluso si está usando la API de verificación remota.

Especifique explícitamente el parámetro audience

Para verificar la declaración, debe realizar un pedido POST a https://verifier.login.persona.org/verify. El pedido incluye el parámetro llamado audience:

assertion=<ASSERTION>&audience=https://mysite.com:443"

El parámetro audience es requerido. Siempre debe especificar explicitamente audience en su código, o en su código de configuración. Especialmente:

  • No confie en el Host header enviado por el navegador del usuario.
  • No confie en el parámetro explicito enviado por el navegador del usuario, pero generado usando JavaScript, e.g. document.location.

Si dejas que el navegador del usuario te envie el parametro audience, esto deja la posiblidad de que un sitio web malicioso pueda reusar las declaraciones de su sitio web para autenticarse en tu sitio web.

Verifica los certificados SSL

Para verificar una declaración, debes realizar un petición POST a https://verifier.login.persona.org/verify. Debes asegurarte que tu petición HTTPS verifique el certificado enviado desde el servidor contra un certificado confiable de administrador. Si no lo haces, un atacante podría presentarse como verifer.login.persona.org y realizar verificaciones falsas.

Check that the library you are using to make the request verifies certificates correctly, and that you are initializing it with the appropriate root certificate(s).

For example, Python 2.7's standard urllib2 module does not validate server certificates. Instead, we recommend using the "requests" or "urllib3" modules in Python 2.x, or the standard http.client.HTTPSConnection class in Python 3.x. For Perl, ensure that you are using at least version 6.0 of libwww-perl. Depending on the language, library, and operating system that you're using, you may need to supply either a list of trusted CA roots or the single CA used by verifier.login.persona.org.

Implement CSRF protection

In a CSRF (Cross-Site Request Forgery) login attack, an attacker uses a cross-site request forgery to log the user into a web site using the attacker's credentials.

For example: a user visits a malicious web site containing a form element. The form's action attribute is set to an HTTP POST request to http://www.google.com/login, supplying the attacker's username and password. When the user submits the form, the request is sent to Google, the login succeeds and the Google server sets a cookie in the user's browser. Now the user's unknowingly logged into the attacker's Google account.

The attack can be used to gather sensitive information about the user. For example, Google's Web History feature logs all the user's Google search terms. If a user is logged into the attacker's Google account and the attacker has Web History enabled, then the user is giving the attacker all this information.

CSRF login attacks, and potential defenses against them, are documented more fully in Robust Defenses for Cross-Site Request Forgery (PDF). They're not specific to Persona: most login mechanisms are potentially vulnerable to them.

There are a variety of techniques which can be used to protect a site from CSRF login attacks, which are documented more fully in the study above.

One approach is to create a secret identifier in the server, shared with the browser, and require the browser to supply in when making login requests. For example:

  1. As soon as the user lands on your site, before they try to log in, create a session for them on the server. Store the session ID in a browser cookie.
  2. On the server, generate a random string of at least 10 alphanumeric characters. A randomly generated UUID is a good option. This is the CSRF token. Store it in the session.
  3. Deliver the CSRF token to the browser by either embedding it in JavaScript or HTML as a hidden form variable.
  4. Ensure that the AJAX submission or form POST includes the CSRF token.
  5. On the server side, before accepting an assertion, check that the submitted CSRF token matches the session-stored CSRF token.

Enhancements

Content Security Policy (CSP)

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware.

If you use CSP on your site, you may need to tweak your policy to enable Persona. Depending on your policy, you may need to:

  • Remove inline javascript: URIs and replace them with code loaded from an additional script file. The file can look up elements based on their ID, and then attach to the element by setting {{ domxref("element.onclick", "onclick") }} or calling {{ domxref("element.addEventListener()", "addEventListener()") }}.
  • Allow https://login.persona.org as both a script-src and frame-src so that your site can load the remote include.js file and that file can communicate with the fallback Persona implementation.

An example Apache configuration might include:

Header set X-Content-Security-Policy: "default-src 'self'; frame-src 'self' https://login.persona.org ; script-src 'self' https://login.persona.org"

Revision Source

<p>Cuando agregas a tu sitio web soporte para Persona, Persona toma tantas medidas de seguridad como puede. Sin embargo, algunas medidas de seguridad solo pueden ser manejados por tu sitio web. Estas son listadas a continuación.</p>
<h2 id="Essential_practices" name="Essential_practices">Prácticas Esenciales</h2>
<h3 id="Verify_assertions_on_your_server" name="Verify_assertions_on_your_server">Verificar la confirmación en tu servidor</h3>
<p>Cuando utilizas Persona, las declaraciones de identidad son pasada dentro de la función <code>onlogin</code> a través de</p>
<p>{{ domxref("navigator.id.watch()") }}</p>
<p><em>Siempre</em> debes pasar la declaración a tu servidor para verificarla, y solo tu servidor debe decidir si autorizar al usuario permisos adicionales en base al resultado de la verificación:</p>
<pre class="brush:js;">
// Inside navigator.id.watch({ ...
onlogin: function(assertion) {
  // A user wants to log in! Here you need to:
  // 1. Send the assertion to your backend for verification and to create a session.
  // 2. Update your UI.
},
</pre>
<p>Si trata de verifcar la declaración usando JavaScript ejecutandose en el navegador del usuario, algún usuario malicioso podría suplantar por otro usuario legítimo de su sitio inyectando código bloqueando tu código JavaScript. Esto es posible debido a que no se tiene control del navegador del usuario, donde se ejecuta el código.</p>
<p>Como mencionamos lineas arriba, <em>siempre</em> debe pasar la declaración a su servidor para la verificación. Incluso si está usando la API de verificación remota.</p>
<h3 id="Explicitly_specify_the_audience_parameter" name="Explicitly_specify_the_audience_parameter">Especifique explícitamente el parámetro <code>audience</code></h3>
<p>Para verificar la declaración, debe realizar un pedido <code>POST</code> a<code> https://verifier.login.persona.org/verify</code>. El pedido incluye el parámetro llamado <code>audience</code>:</p>
<pre>
<code>assertion=&lt;ASSERTION&gt;&amp;audience=https://mysite.com:443"</code></pre>
<p>El parámetro <code>audience</code> es requerido. Siempre debe especificar explicitamente audience en su código, o en su código de configuración. Especialmente:</p>
<ul>
  <li>No confie en el Host header enviado por el navegador del usuario.</li>
  <li>No confie en el parámetro explicito enviado por el navegador del usuario, pero generado usando JavaScript, e.g. <code>document.location</code>.</li>
</ul>
<p>Si dejas que el navegador del usuario te envie el parametro <code>audience</code>, esto deja la posiblidad de que un sitio web malicioso pueda reusar las declaraciones de su sitio web para autenticarse en tu sitio web.</p>
<h3 id="Verify_SSL_certificates" name="Verify_SSL_certificates">Verifica los certificados SSL</h3>
<p>Para verificar una declaración, debes realizar un petición POST a <code>https://verifier.login.persona.org/verify</code>. Debes asegurarte que tu petición HTTPS verifique el certificado enviado desde el servidor contra un certificado confiable de administrador. Si no lo haces, un atacante podría presentarse como <code>verifer.login.persona.org</code> y realizar verificaciones falsas.</p>
<p>Check that the library you are using to make the request verifies certificates correctly, and that you are initializing it with the appropriate root certificate(s).</p>
<p>For example, Python 2.7's standard <a class="external" href="http://docs.python.org/release/2.7.3/library/urllib2.html#urllib2.urlopen" title="http://docs.python.org/release/2.7.3/library/urllib2.html#urllib2.urlopen">urllib2 module</a> does not validate server certificates. Instead, we recommend using the "<a class="external" href="http://pypi.python.org/pypi/requests">requests</a>" or "<a class="external" href="http://pypi.python.org/pypi/urllib3" title="http://pypi.python.org/pypi/urllib3">urllib3</a>" modules in Python 2.x, or the standard <code>http.client.HTTPSConnection</code> class in Python 3.x. For Perl, ensure that you are using at least version 6.0 of <code>libwww-perl</code>. Depending on the language, library, and operating system that you're using, you may need to supply either a list of trusted CA roots or the single CA used by <code>verifier.login.persona.org</code>.</p>
<h3 id="Implement_CSRF_protection" name="Implement_CSRF_protection">Implement CSRF protection</h3>
<p>In a CSRF (Cross-Site Request Forgery) login attack, an attacker uses a cross-site request forgery to log the user into a web site using the attacker's credentials.</p>
<p>For example: a user visits a malicious web site containing a <code>form</code> element. The form's <code>action</code> attribute is set to an HTTP POST request to <a class="external" href="http://www.google.com/login" title="http://www.google.com/login">http://www.google.com/login</a>, supplying the attacker's username and password. When the user submits the form, the request is sent to Google, the login succeeds and the Google server sets a cookie in the user's browser. Now the user's unknowingly logged into the attacker's Google account.</p>
<p>The attack can be used to gather sensitive information about the user. For example, Google's <a class="link-https" href="https://www.google.com/history/">Web History</a> feature logs all the user's Google search terms. If a user is logged into the attacker's Google account and the attacker has Web History enabled, then the user is giving the attacker all this information.</p>
<p>CSRF login attacks, and potential defenses against them, are documented more fully in <a class="external" href="http://www.adambarth.com/papers/2008/barth-jackson-mitchell-b.pdf">Robust Defenses for Cross-Site Request Forgery</a> (PDF). They're not specific to Persona: most login mechanisms are potentially vulnerable to them.</p>
<p>There are a variety of techniques which can be used to protect a site from CSRF login attacks, which are documented more fully in the study above.</p>
<p>One approach is to create a secret identifier in the server, shared with the browser, and require the browser to supply in when making login requests. For example:</p>
<ol>
  <li>As soon as the user lands on your site, before they try to log in, create a session for them on the server. Store the session ID in a browser cookie.</li>
  <li>On the server, generate a random string of at least 10 alphanumeric characters. A randomly generated UUID is a good option. This is the CSRF token. Store it in the session.</li>
  <li>Deliver the CSRF token to the browser by either embedding it in JavaScript or HTML as a hidden form variable.</li>
  <li>Ensure that the AJAX submission or form POST includes the CSRF token.</li>
  <li>On the server side, before accepting an assertion, check that the submitted CSRF token matches the session-stored CSRF token.</li>
</ol>
<h2 id="Enhancements" name="Enhancements">Enhancements</h2>
<h3 id="Content_Security_Policy_(CSP)" name="Content_Security_Policy_(CSP)">Content Security Policy (CSP)</h3>
<p><a href="/en-US/docs/Security/CSP" title="Security/CSP">Content Security Policy</a> (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware.</p>
<p>If you use CSP on your site, you may need to tweak your policy to enable Persona. Depending on your policy, you may need to:</p>
<ul>
  <li>Remove inline <code>javascript:</code> URIs and replace them with code loaded from an additional script file. The file can look up elements based on their ID, and then attach to the element by setting {{ domxref("element.onclick", "onclick") }} or calling {{ domxref("element.addEventListener()", "addEventListener()") }}.</li>
  <li>Allow <code>https://login.persona.org</code> as both a <code>script-src</code> and <code>frame-src</code> so that your site can load the remote <code>include.js</code> file and that file can communicate with the fallback Persona implementation.</li>
</ul>
<p>An example Apache configuration might include:</p>
<pre>
<span class="diff-content"><span class="idiff">Header set X-Content-Security-Policy: "default-src 'self'; frame-src 'self' https://login.persona.org ; script-src 'self' https://login.persona.org"</span></span></pre>
Revert to this revision