diff --git a/security-guide/ch_dashboard.xml b/security-guide/ch_dashboard.xml index a1c56eba..95b127c3 100644 --- a/security-guide/ch_dashboard.xml +++ b/security-guide/ch_dashboard.xml @@ -22,228 +22,20 @@ and has good deployment and configuration documentation. -
- Basic web server configuration - 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 lightweight and easier to configure - correctly. - When using nginx, we recommend gunicorn as the WSGI host with an appropriate number - of synchronous workers. When using Apache, we recommend - mod_wsgi to host the dashboard. -
-
- HTTPS - - Deploy the dashboard behind a secure - HTTPS server by 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. - Configure HTTP requests to the dashboard domain to redirect - to the fully qualified HTTPS URL. -
-
- HTTP Strict Transport Security (HSTS) - It is highly recommended to use HTTP Strict Transport - Security (HSTS). - - If you are using an HTTPS proxy in front of your web - server, rather than using an HTTP server with HTTPS - functionality, modify the SECURE_PROXY_SSL_HEADER - variable. Refer to the Django documentation for information about modifying the - SECURE_PROXY_SSL_HEADER variable. - - See the chapter on PKI/SSL Everywhere for more specific - recommendations and server configurations for HTTPS - configurations, including the configuration of HSTS. -
-
- Front end caching - Since the dashboard is rendering dynamic content passed directly - from OpenStack API requests, we do not recommend front end - caching layers such as varnish. In Django, static media is - directly served from Apache or nginx and already benefits from - web host caching. -
-
- Domain names - 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 name server - maintenance. - We strongly recommend deploying horizon to a - second-level domain, such as - https://example.com, and advise against deploying - horizon on a shared subdomain of any level, - for example https://openstack.example.org or - https://horizon.openstack.example.org. We also - advise against deploying to bare internal domains like - https://horizon/. These recommendations are based on the - limitations of browser same-origin-policy. - Recommendations given in this guide cannot effectively guard against - known attacks if you deploy the dashboard in a domain that also hosts - user-generated content, even when this content resides on a separate - sub-domain. User-generated content can consist of scripts, images, or uploads - of any type. Most major web presences, including googleusercontent.com, - fbcdn.com, github.io, and twimg.co, use this approach to segregate - user-generated content from cookies and security tokens. - If you do not follow this recommendation regarding - second-level domains, avoid a cookie-backed session store and - employ HTTP Strict Transport Security (HSTS). When deployed on - a subdomain, the dashboard's security is equivalent to the least secure - application deployed on the same second-level domain. -
-
- Static media - The 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. - Django media settings are documented in the Django documentation. - Dashboard's default configuration uses django_compressor to compress and minify CSS and - JavaScript content before serving it. This process should be - statically done before deploying the 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 compression entirely. Online compression dependencies - (less, Node.js) should not be installed on production - machines. -
-
- Secret key - The dashboard depends on a shared - setting for some security functions. The secret key should be a - randomly generated string at least 64 characters long, which must - be shared across all active dashboard 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. -
-
- Session back end - Horizon's default session back end - (django.contrib.sessions.backends.signed_cookies) - stores user data in signed but - unencrypted cookies stored in the - browser. This approach allows the most simple session back-end - scaling since each dashboard instance is stateless, but it comes - at the cost of storing sensitive access tokens in the - client browser and transmitting them with every - request. This back end ensures that session data has not been - tampered with, but the data itself is not encrypted other than - the encryption provided by HTTPS. - If your architecture allows it, we recommend using - django.contrib.sessions.backends.cache as - your session back end 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 - back end, refer to the Django documentation understand the - security trade-offs. - For further details, see the Django documentation. -
-
- Allowed hosts - Configure the setting with - the domain or domains where the dashboard is available. Failure - to configure this setting (especially if not following the - recommendation above regarding second level domains) opens the - dashboard to a number of serious attacks. Wild card domains - should be avoided. - For further details, see the Django documentation. -
-
- Cross Site Request Forgery (CSRF) - Django has dedicated middleware for cross-site request forgery (CSRF). - For further details, see the - Django documentation. - 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. -
-
- Cookies - Session Cookies should be set to HTTPONLY: - SESSION_COOKIE_HTTPONLY = True - Never configure CSRF or session cookies to have a wild card - domain with a leading dot. Horizon's session and CSRF cookie - should be secured when deployed with HTTPS: - CSRF_COOKIE_SECURE = True -SESSION_COOKIE_SECURE = True -
-
- Cross Site Scripting (XSS) - Unlike many similar systems, the 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). - 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 - auto escape - is turned off, and any JavaScript which might evaluate - improperly escaped data. -
-
- Cross Origin Resource Sharing (CORS) - Configure your web server to send a restrictive CORS header - with each response, allowing only the dashboard domain and - protocol: - Access-Control-Allow-Origin: https://example.com/ - Never allow the wild card origin. -
-
- Horizon image upload - We recommend that implementers disable HORIZON_IMAGES_ALLOW_UPLOAD unless they have - implemented a plan to prevent resource exhaustion and denial of - service. -
-
- Upgrading - 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. -
-
- Debug - - We recommend that the setting - is set to False in production environments. - If is set to True, - Django will display stack traces and sensitive web server - state information when exceptions are thrown. -
+ + + + + + + + + + + + + + + + diff --git a/security-guide/section_dashboard-allowed-hosts.xml b/security-guide/section_dashboard-allowed-hosts.xml new file mode 100644 index 00000000..3b5abaf0 --- /dev/null +++ b/security-guide/section_dashboard-allowed-hosts.xml @@ -0,0 +1,18 @@ + +
+ + Allowed hosts + Configure the setting with + the domain or domains where the dashboard is available. Failure + to configure this setting (especially if not following the + recommendation above regarding second level domains) opens the + dashboard to a number of serious attacks. Wild card domains + should be avoided. + For further details, see the Django documentation. +
diff --git a/security-guide/section_dashboard-basic-web-server-configuration.xml b/security-guide/section_dashboard-basic-web-server-configuration.xml new file mode 100644 index 00000000..7a618904 --- /dev/null +++ b/security-guide/section_dashboard-basic-web-server-configuration.xml @@ -0,0 +1,19 @@ + +
+ + Basic web server configuration + 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 lightweight and easier to configure + correctly. + When using nginx, we recommend gunicorn as the WSGI host with an appropriate number + of synchronous workers. When using Apache, we recommend + mod_wsgi to host the dashboard. +
diff --git a/security-guide/section_dashboard-cookies.xml b/security-guide/section_dashboard-cookies.xml new file mode 100644 index 00000000..3e9272ba --- /dev/null +++ b/security-guide/section_dashboard-cookies.xml @@ -0,0 +1,16 @@ + +
+ + Cookies + Session Cookies should be set to HTTPONLY: + SESSION_COOKIE_HTTPONLY = True + Never configure CSRF or session cookies to have a wild card + domain with a leading dot. Horizon's session and CSRF cookie + should be secured when deployed with HTTPS: + CSRF_COOKIE_SECURE = True + SESSION_COOKIE_SECURE = True +
diff --git a/security-guide/section_dashboard-cross-origin-resource-sharing-cors.xml b/security-guide/section_dashboard-cross-origin-resource-sharing-cors.xml new file mode 100644 index 00000000..21ee07d3 --- /dev/null +++ b/security-guide/section_dashboard-cross-origin-resource-sharing-cors.xml @@ -0,0 +1,14 @@ + +
+ + Cross Origin Resource Sharing (CORS) + Configure your web server to send a restrictive CORS header + with each response, allowing only the dashboard domain and + protocol: + Access-Control-Allow-Origin: https://example.com/ + Never allow the wild card origin. +
diff --git a/security-guide/section_dashboard-cross-site-request-forgery-csrf.xml b/security-guide/section_dashboard-cross-site-request-forgery-csrf.xml new file mode 100644 index 00000000..72559277 --- /dev/null +++ b/security-guide/section_dashboard-cross-site-request-forgery-csrf.xml @@ -0,0 +1,19 @@ + +
+ + Cross Site Request Forgery (CSRF) + Django has dedicated middleware for cross-site request forgery (CSRF). + For further details, see the + Django documentation. + 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. +
diff --git a/security-guide/section_dashboard-cross-site-scripting-xss.xml b/security-guide/section_dashboard-cross-site-scripting-xss.xml new file mode 100644 index 00000000..ea2811b9 --- /dev/null +++ b/security-guide/section_dashboard-cross-site-scripting-xss.xml @@ -0,0 +1,22 @@ + +
+ + Cross Site Scripting (XSS) + Unlike many similar systems, the 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). + 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 + auto escape + is turned off, and any JavaScript which might evaluate + improperly escaped data. +
diff --git a/security-guide/section_dashboard-debug.xml b/security-guide/section_dashboard-debug.xml new file mode 100644 index 00000000..89b7a3ef --- /dev/null +++ b/security-guide/section_dashboard-debug.xml @@ -0,0 +1,14 @@ + +
+ + Debug + We recommend that the setting + is set to False in production environments. + If is set to True, + Django will display stack traces and sensitive web server + state information when exceptions are thrown. +
diff --git a/security-guide/section_dashboard-domain-names.xml b/security-guide/section_dashboard-domain-names.xml new file mode 100644 index 00000000..fcf597e9 --- /dev/null +++ b/security-guide/section_dashboard-domain-names.xml @@ -0,0 +1,37 @@ + +
+ Domain names + 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 name server + maintenance. + We strongly recommend deploying horizon to a + second-level domain, such as + https://example.com, and advise against deploying + horizon on a shared subdomain of any level, + for example https://openstack.example.org or + https://horizon.openstack.example.org. We also + advise against deploying to bare internal domains like + https://horizon/. These recommendations are based on the + limitations of browser same-origin-policy. + Recommendations given in this guide cannot effectively guard against + known attacks if you deploy the dashboard in a domain that also hosts + user-generated content, even when this content resides on a separate + sub-domain. User-generated content can consist of scripts, images, or uploads + of any type. Most major web presences, including googleusercontent.com, + fbcdn.com, github.io, and twimg.co, use this approach to segregate + user-generated content from cookies and security tokens. + If you do not follow this recommendation regarding + second-level domains, avoid a cookie-backed session store and + employ HTTP Strict Transport Security (HSTS). When deployed on + a subdomain, the dashboard's security is equivalent to the least secure + application deployed on the same second-level domain. +
diff --git a/security-guide/section_dashboard-front-end-caching.xml b/security-guide/section_dashboard-front-end-caching.xml new file mode 100644 index 00000000..4b471b0e --- /dev/null +++ b/security-guide/section_dashboard-front-end-caching.xml @@ -0,0 +1,14 @@ + +
+ + Front end caching + Since the dashboard is rendering dynamic content passed directly + from OpenStack API requests, we do not recommend front end + caching layers such as varnish. In Django, static media is + directly served from Apache or nginx and already benefits from + web host caching. +
diff --git a/security-guide/section_dashboard-horizon-image-upload.xml b/security-guide/section_dashboard-horizon-image-upload.xml new file mode 100644 index 00000000..b1558dab --- /dev/null +++ b/security-guide/section_dashboard-horizon-image-upload.xml @@ -0,0 +1,14 @@ + +
+ + Horizon image upload + We recommend that implementers disable HORIZON_IMAGES_ALLOW_UPLOAD unless they have + implemented a plan to prevent resource exhaustion and denial of + service. +
diff --git a/security-guide/section_dashboard-http-strict-transport-security-hsts.xml b/security-guide/section_dashboard-http-strict-transport-security-hsts.xml new file mode 100644 index 00000000..c4f97ea6 --- /dev/null +++ b/security-guide/section_dashboard-http-strict-transport-security-hsts.xml @@ -0,0 +1,23 @@ + +
+ + HTTP Strict Transport Security (HSTS) + It is highly recommended to use HTTP Strict Transport + Security (HSTS). + + If you are using an HTTPS proxy in front of your web + server, rather than using an HTTP server with HTTPS + functionality, modify the SECURE_PROXY_SSL_HEADER + variable. Refer to the Django documentation for information about modifying the + SECURE_PROXY_SSL_HEADER variable. + + See the chapter on PKI/SSL Everywhere for more specific + recommendations and server configurations for HTTPS + configurations, including the configuration of HSTS. +
diff --git a/security-guide/section_dashboard-https.xml b/security-guide/section_dashboard-https.xml new file mode 100644 index 00000000..7857ab8b --- /dev/null +++ b/security-guide/section_dashboard-https.xml @@ -0,0 +1,18 @@ + +
+ + HTTPS + + Deploy the dashboard behind a secure + HTTPS server by 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. + Configure HTTP requests to the dashboard domain to redirect + to the fully qualified HTTPS URL. +
diff --git a/security-guide/section_dashboard-secret-key.xml b/security-guide/section_dashboard-secret-key.xml new file mode 100644 index 00000000..8f77e65f --- /dev/null +++ b/security-guide/section_dashboard-secret-key.xml @@ -0,0 +1,16 @@ + +
+ + Secret key + The dashboard depends on a shared + setting for some security functions. The secret key should be a + randomly generated string at least 64 characters long, which must + be shared across all active dashboard 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. +
diff --git a/security-guide/section_dashboard-session-back-end.xml b/security-guide/section_dashboard-session-back-end.xml new file mode 100644 index 00000000..37c345d8 --- /dev/null +++ b/security-guide/section_dashboard-session-back-end.xml @@ -0,0 +1,30 @@ + +
+ + Session back end + Horizon's default session back end + (django.contrib.sessions.backends.signed_cookies) + stores user data in signed but + unencrypted cookies stored in the + browser. This approach allows the most simple session back-end + scaling since each dashboard instance is stateless, but it comes + at the cost of storing sensitive access tokens in the + client browser and transmitting them with every + request. This back end ensures that session data has not been + tampered with, but the data itself is not encrypted other than + the encryption provided by HTTPS. + If your architecture allows it, we recommend using + django.contrib.sessions.backends.cache as + your session back end 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 + back end, refer to the Django documentation understand the + security trade-offs. + For further details, see the Django documentation. +
diff --git a/security-guide/section_dashboard-static-media.xml b/security-guide/section_dashboard-static-media.xml new file mode 100644 index 00000000..853865a0 --- /dev/null +++ b/security-guide/section_dashboard-static-media.xml @@ -0,0 +1,29 @@ + +
+ + Static media + The 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. + Django media settings are documented in the Django documentation. + Dashboard's default configuration uses django_compressor to compress and minify CSS and + JavaScript content before serving it. This process should be + statically done before deploying the 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 compression entirely. Online compression dependencies + (less, Node.js) should not be installed on production + machines. +
diff --git a/security-guide/section_dashboard-upgrading.xml b/security-guide/section_dashboard-upgrading.xml new file mode 100644 index 00000000..4ca7a3c0 --- /dev/null +++ b/security-guide/section_dashboard-upgrading.xml @@ -0,0 +1,15 @@ + +
+ + Upgrading + 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. +