openstack-manuals/doc/security-guide/ch025_web-dashboard.xml
Chandan kumar 77ec2d6e4c Added complete Doc Convention to Security Guide.
Change-Id: I8310331f48399310d1a5d7af88bd91fba20ea89c
Partial-Bug: #1121866
2013-12-06 12:01:57 +05:30

100 lines
13 KiB
XML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://docbook.org/ns/docbook" xmlns:db="http://docbook.org/ns/docbook" version="5.0" xml:id="ch025_web-dashboard"><?dbhtml stop-chunking?>
<title>Dashboard</title>
<para>Horizon is the OpenStack dashboard, providing access to a majority of the capabilities available in OpenStack. These include provisioning users, defining instance flavors, uploading VM images, managing networks, setting up security groups, starting instances, and accessing the instances via a console.</para>
<para>The dashboard is based on the Django web framework, therefore secure deployment practices for Django apply directly to Horizon. This guide provides a popular set of Django security recommendations, further information can be found by reading the <link xlink:href="https://docs.djangoproject.com/en/1.5/#security">Django deployment and security documentation</link>.</para>
<para>The dashboard ships with reasonable default security settings, and has good <link xlink:href="http://docs.openstack.org/developer/horizon/topics/deployment.html">deployment and configuration documentation</link>.</para>
<section xml:id="ch025_web-dashboard-idp237648">
<title>Basic Web Server Configuration</title>
<para>The dashboard should be deployed as a Web Services Gateway Interface (WSGI) application behind an HTTPS proxy such as Apache or nginx. If Apache is not already in use, we recommend nginx since it is lighter weight and easier to configure correctly.</para>
<para>When using nginx, we recommend <link xlink:href="http://docs.gunicorn.org/en/latest/deploy.html">gunicorn</link> as the wsgi host with an appropriate number of synchronous workers. We strongly advise against deployments using fastcgi, scgi, or uWSGI. We strongly advise against the use of synthetic performance benchmarks when choosing a wsgi server.</para>
<para>When using Apache, we recommend <link xlink:href="https://docs.djangoproject.com/en/1.5/howto/deployment/wsgi/modwsgi/">mod_wsgi</link> to host dashboard.</para>
</section>
<section xml:id="ch025_web-dashboard-idp240704">
<title>HTTPS</title>
<para>The dashboard should be deployed behind a secure HTTPS server using a valid, trusted certificate from a recognized certificate authority (CA). Private organization-issued certificates are only appropriate when the root of trust is pre-installed in all user browsers.</para>
<para>HTTP requests to the dashboard domain should be configured to redirect to the fully qualified HTTPS URL.</para>
</section>
<section xml:id="ch025_web-dashboard-idp242624">
<title>HTTP Strict Transport Security (HSTS)</title>
<para>It is highly recommended to use HTTP Strict Transport Security (HSTS).</para>
<para>NOTE: If you are using an HTTPS proxy in front of your web server, rather than using an HTTP server with HTTPS functionality, follow the <link xlink:href="https://docs.djangoproject.com/en/1.5/ref/settings/#secure-proxy-ssl-header">Django documentation on modifying the SECURE_PROXY_SSL_HEADER variable</link>.</para>
<para>See the chapter on PKI/SSL Everywhere for more specific recommendations and server configurations for HTTPS configurations, including the configuration of HSTS.</para>
</section>
<section xml:id="ch025_web-dashboard-idp245456">
<title>Frontend Caching</title>
<para>Since dashboard is rendering dynamic content passed directly from OpenStack API requests, we do not recommend frontend caching layers such as varnish. In Django, static media is directly served from Apache or nginx and already benefits from web host caching.</para>
</section>
<section xml:id="ch025_web-dashboard-idp246880">
<title>Domain Names</title>
<para>Many organizations typically deploy web applications at subdomains of an overarching organization domain. It is natural for users to expect a domain of the form openstack.example.org. In this context, there are often many other applications deployed in the same second-level namespace, often serving user-controlled content. This name structure is convenient and simplifies nameserver maintenance.</para>
<para>We strongly recommend deploying horizon to a <emphasis>second-level domain</emphasis>, for example <uri>https://example.com</uri>, and advise against deploying horizon on a<emphasis> shared subdomain</emphasis> of any level, for example <uri>https://openstack.example.org</uri> or <uri>https://horizon.openstack.example.org</uri>. We also advise against deploying to bare internal domains like <uri>https://horizon/</uri>.</para>
<para>This recommendation is based on the limitations browser same-origin-policy. The recommendations in this guide cannot effectively protect users against known attacks if dashboard is deployed on a domain which also hosts user-generated content (e.g. scripts, images, uploads of any kind) even if the user-generated content is on a different subdomain. This approach is used by most major web presences (e.g. googleusercontent.com, fbcdn.com, github.io, twimg.com) to ensure that user generated content stays separate from cookies and security tokens.</para>
<para>Additionally, if you decline to follow this recommendation above about second-level domains, it is vital that you avoid the cookie backed session store and employ HTTP Strict Transport Security (HSTS). When deployed on a subdomain, dashboard's security is only as strong as the weakest application deployed on the same second-level domain.</para>
</section>
<section xml:id="ch025_web-dashboard-idp251760">
<title>Static Media</title>
<para>Dashboard's static media should be deployed to a subdomain of the dashboard domain and served by the web server. The use of an external content delivery network (CDN) is also acceptable. This subdomain should not set cookies or serve user-provided content. The media should also be served with HTTPS.</para>
<para>Django media settings are documented at <link xlink:href="https://docs.djangoproject.com/en/1.5/ref/settings/#static-root">https://docs.djangoproject.com/en/1.5/ref/settings/#static-root</link>.</para>
<para>Dashboard's default configuration uses <link xlink:href="http://django-compressor.readthedocs.org/">django_compressor</link> to compress and minify css and JavaScript content before serving it. This process should be statically done before deploying dashboard, rather than using the default in-request dynamic compression and copying the resulting files along with deployed code or to the CDN server. Compression should be done in a non-production build environment. If this is not practical, we recommend disabling resource minification entirely. Online compression dependencies (less, nodejs) should not be installed on production machines.</para>
</section>
<section xml:id="ch025_web-dashboard-idp255696">
<title>Secret Key</title>
<para>Dashboard depends on a shared SECRET_KEY setting for some security functions. It should be a randomly generated string at least 64 characters long. It must be shared across all active Horizon instances. Compromise of this key may allow a remote attacker to execute arbitrary code. Rotating this key invalidates existing user sessions and caching. Do not commit this key to public repositories.</para>
</section>
<section xml:id="ch025_web-dashboard-idp257248">
<title>Session Backend</title>
<para>Horizon's default session backend (<emphasis>django.contrib.sessions.backends.signed_cookies</emphasis>) stores user data in <emphasis>signed</emphasis> but <emphasis>unencrypted </emphasis>cookies stored in the browser. This approach allows the most simple session backend scaling since each Horizon instance is stateless, but it comes at the cost of <emphasis>storing sensitive access tokens in the client browser</emphasis> and transmitting them with every request. This backend ensures that session data has not been tampered with, but the data itself is not encrypted other than the encryption provided by HTTPS.</para>
<para>If your architecture allows it, we recommend using <emphasis>django.contrib.sessions.backends.cache</emphasis> as your session backend with memcache as the cache. Memcache must not be exposed publicly, and should communicate over a secured private channel. If you choose to use the signed cookies backend, refer to the Django documentation understand the security tradeoffs.</para>
<para>For further details, consult the <link xlink:href="https://docs.djangoproject.com/en/1.5/topics/http/sessions/#configuring-the-session-engine">Django session backend documentation</link>.</para>
</section>
<section xml:id="ch025_web-dashboard-idp262288">
<title>Allowed Hosts</title>
<para>Configure the ALLOWED_HOSTS setting with the domain or domains where Horizon is available. Failure to configure this setting (especially if not following the recommendation above regarding second level domains) opens Horizon to a number of serious attacks. Wildcard domains should be avoided.</para>
<para>For further details, see the <link xlink:href="https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts">Django documentation on settings</link>.</para>
</section>
<section xml:id="ch025_web-dashboard-idp264272">
<title>Cookies</title>
<para>Session Cookies should be set to HTTPONLY:</para>
<screen> 
SESSION_COOKIE_HTTPONLY = True</screen>
<para>Never configure CSRF or session cookies to have a wildcard domain with a leading dot. Horizon's session and CSRF cookie should be secured when deployed with HTTPS:</para>
<screen> 
Code CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True</screen>
</section>
<section xml:id="ch025_web-dashboard-idp266976">
<title>Password Auto Complete</title>
<para>We recommend that implementers do not change the default password autocomplete behavior. Users choose stronger passwords in environments that allow them to use the secure browser password manager. Organizations which forbid the browser password manager should enforce this policy at the desktop level.</para>
</section>
<section xml:id="ch025_web-dashboard-idp268448">
<title>Cross Site Request Forgery (CSRF)</title>
<para>Django has a dedicated middleware for <link xlink:href="https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#how-it-works">cross-site request forgery</link> (CSRF).</para>
<para>Dashboard is designed to discourage developers from introducing cross-site scripting vulnerabilities with custom dashboards. However, it is important to audit custom dashboards, especially ones that are javascript-heavy for inappropriate use of the @csrf_exempt decorator. Dashboards which do not follow these recommended security settings should be carefully evaluated before restrictions are relaxed.</para>
</section>
<section xml:id="ch025_web-dashboard-idp270608">
<title>Cross Site Scripting (XSS)</title>
<para>Unlike many similar systems, OpenStack dashboard allows the entire unicode character set in most fields. This means developers have less latitude to make escaping mistakes that open attack vectors for cross-site scripting (XSS).</para>
<para>Dashboard provides tools for developers to avoid creating XSS vulnerabilities, but they only work if developers use them correctly. Audit any custom dashboards, paying particular attention to use of the mark_safe function, use of is_safe with custom template tags, the safe template tag, anywhere autoescape is turned off, and any javascript which might evaluate improperly escaped data.</para>
</section>
<section xml:id="ch025_web-dashboard-idp272832">
<title>Cross Origin Resource Sharing (CORS)</title>
<para>Configure your web server to send a restrictive CORS header with each response, allowing only the Horizon domain and protocol:</para>
<screen>
Access-Control-Allow-Origin: https://example.com/</screen>
<para>Never allow the wildcard origin.</para>
</section>
<section xml:id="ch025_web-dashboard-idp275056">
<title>Horizon Image Upload</title>
<para>We recommend that implementers <link xlink:href="http://docs.openstack.org/developer/horizon/topics/deployment.html#file-uploads">disable HORIZON_IMAGES_ALLOW_UPLOAD</link> unless they have implemented a plan to prevent resource exhaustion and denial of service.</para>
</section>
<section xml:id="ch025_web-dashboard-idp276864">
<title>Upgrading</title>
<para>Django security releases are generally well tested and aggressively backwards compatible. In almost all cases, new major releases of Django are also fully backwards compatible with previous releases. Dashboard implementers are strongly encouraged to run the latest stable release of Django with up-to-date security releases.</para>
</section>
<section xml:id="ch025_web-dashboard-idp278672">
<title>Debug</title>
<para>Make sure DEBUG is set to False in production. In Django, DEBUG displays stack traces and sensitive web server state information on any exception.</para>
</section>
</chapter>