Repository : http://git.fedorahosted.org/git/?p=secure-coding.git On branch : master >--------------------------------------------------------------- commit a650892eb864fce2d6168071e01ac3cba9e5a056 Author: Eric Christensen <echriste@xxxxxxxxxx> Date: Fri Jun 27 11:09:50 2014 -0400 Marked up more fo this chapter >--------------------------------------------------------------- ...b_Applications.xml => Web_Applications.xml.txt} | 441 ++++++++++---------- 1 files changed, 222 insertions(+), 219 deletions(-) diff --git a/defensive-coding/en-US/Web_Applications.xml b/defensive-coding/en-US/Web_Applications.xml.txt similarity index 87% copy from defensive-coding/en-US/Web_Applications.xml copy to defensive-coding/en-US/Web_Applications.xml.txt index b08d0d7..e1f270a 100644 --- a/defensive-coding/en-US/Web_Applications.xml +++ b/defensive-coding/en-US/Web_Applications.xml.txt @@ -21,7 +21,7 @@ <para>An attacker could in theory create a link that contains Javascript that will be executed in the victims browser like so:</para> <code> -http://example.com/?name=<script>alert(1)</script> +http://example.com/?name=<script>alert(1)</script> </code> </section> <section> @@ -40,10 +40,10 @@ http://example.com/?name=<script>alert(1)</script> <code> Will be escaped -<h:outputText value="#{param.name}"> +<h:outputText value="#{param.name}"> Won't be escaped (DON'T DO THIS!) -<h:outputText value="#{param.name}" escape=false> +<h:outputText value="#{param.name}" escape=false> </code> <para>Similarly Flask templates will escape content by default unless explicitly told not to.</para> @@ -62,7 +62,7 @@ from flask import g, request, flash, abort, escape @app.route('/say_hello') def say_hello(): - return "<p>Hi %s</p>" % (escape(request.args.get('name'))) + return "<p>Hi %s</p>" % (escape(request.args.get('name'))) </code> <para>You can also do this directly in Java code using Apache commons</para> @@ -70,7 +70,7 @@ def say_hello(): import static org.apache.commons.lang.StringEscapeUtils.escapeHtml; void doGet(...){ - response.getWriter().printf("<p>Hello, %s</p>", escapeHtml(request.getParameter("name"))); + response.getWriter().printf("<p>Hello, %s</p>", escapeHtml(request.getParameter("name"))); } </code> @@ -78,7 +78,7 @@ void doGet(...){ <para>You should *NOT* try to implement your own escaping mechanisms or blacklists when a better, security tested alternative is available.</para> </important> - <para>Some caveats around how to escape content correctly and safely will be covered in more details in the <<_output_escaping_and_encoding,output escaping and encoding>> section.</para> + <para>Some caveats around how to escape content correctly and safely will be covered in more details in the <_output_escaping_and_encoding,output escaping and encoding>> section.</para> <section> <title>Monitoring and validating HTTP parameters</title> @@ -120,48 +120,48 @@ def xss_protection(rsp): <para>The trouble with XSS from a browser's perspective is that is difficult to distinguish between a script that's intended to be part of a web application and a script that has been injected by an attacker. Content Security Policy (CSP) is a standard that allows application developers to specify whitelists of trusted sources for their content.</para> <para>There are however some caveats to using this feature. In-lined content is considered harmful so all content must be loadable from an external source. This means that you cannot embed scripts and styles within HTML content.</para> <code> -<!-- +<!-- You can no longer use inline content when working with CSP. This is an example of things that will no longer work. ---> -<html> - <head> - <title>Example</title> - <!-- +--> +<html> + <head> + <title>Example</title> + <!-- All styles need to be loaded from an explicit source rather than being embedded in a page. - --> - <style> + --> + <style> #foo { padding-top: 2em; margin-left: 1.5em; }; - </style> - </head> - <body> - <div id="foo"> - <h1>Example</h1> - <p> + </style> + </head> + <body + <div id="foo"> + <h1>Example</h1> + <p> This is an example of the kind of things that you can no longer do. - You can't invoke <a id='say_hello' href="javascript:sayHello()">javascript via links</a> + You can't invoke <a id='say_hello' href="javascript:sayHello()">javascript via links</a> anymore. - </p> - <p id="bad_style" style="color:red"> + </p> + <p id="bad_style" style="color:red"> Inline styles are also prevented. - </p> - </div> + </p> + </div> - <!-- + <!-- All scripts need to be loaded from an explicit source rather than being embedded in a page. - --> - <script> + --> + <script> function sayHello(){ alert("Hello world"); } - </script> - </body> -</html> + </script> + </body> +</html> </code> <para>Instead you should load content from an explicit source. For example the previous code snippet may be rewritten as follows.</para> <code> @@ -186,30 +186,30 @@ document.addEventListner('DOMContentLoaded', function(){ }); </code> <code> -<html> - <head> - <link rel="stylesheet" type="text/css" href="hello.css"> - </head> - <body> - <div id="foo"> - <h1>Example</h1> - <p> +<html> + <head> + <link rel="stylesheet" type="text/css" href="hello.css"> + </head> + <body> + <div id="foo"> + <h1>Example</h1> + <p> In this example the scripts and styles are loaded from - an external source. The onclick event handler of <a id='say_hello' href="#">this link</a> + an external source. The onclick event handler of <a id='say_hello' href="#">this link</a> is handled by the external javascript source file. This can be used with CSP. - </p> - <p id="bad_style"> + </p> + <p id="bad_style"> Similarly the style of this paragrah is managed by the external CSS source. This approach can also be used with CSP. - </p> - </div> - <script type="text/javascript" src="hello.js"></script> - </body> -</html> + </p> + </div> + <script type="text/javascript" src="hello.js"></script> + </body> +</html> </code> <para>The content security policy can be set using the following headers:</para> - +<code> [options="header"] |=== | Header | Browsers @@ -224,10 +224,10 @@ document.addEventListner('DOMContentLoaded', function(){ | Chrome 14+, Safari 6+ |=== - -When specifying the header you can create a fine grained policy using a combination -of the following directives: - +</code> +<para>When specifying the header you can create a fine grained policy using a combination +of the following directives:</para> +</code> [options="header"] |=== | Directive | Description @@ -241,7 +241,7 @@ within the web application. | Allows you to set policy around valid sources for Javascript content. | object-src -| Defines valid sources of plugins such as <object>, <embed>, and <applet>. +| Defines valid sources of plugins such as <object>, <embed>, and <applet>. | style-src | Allows you to set policy around valid sources for stylesheets. @@ -251,7 +251,7 @@ within the web application. | media-src | Allows you to set policy around valid sources of HTML5 content like -<audio> and <video>. +<audio> and <video>. | frame-src | Allows you to set policy around valid sources for loading frames. @@ -283,12 +283,12 @@ specify the URI to send the CSP report to. |=== - -Most of these directives need to be applied to a source to be enforced by the browser. +</code> +<para>Most of these directives need to be applied to a source to be enforced by the browser. The exceptions being the sandbox and report-uri directives which have their own special purposes. For ther other directives you may enforce your whitelist by selective usage -of the following sources. - +of the following sources. </para> +<code> [options="headers"] |=== | Source | Description @@ -312,14 +312,16 @@ of the following sources. | An explicit URI to load content from. |=== - +</code> +<para> Creating a policy requires knowing where your web assets are coming from and restricting external sources as much as possible. Most web applications will be able to get away with disabling media, embedded content and frames entirely. The best way to retrofit a policy is to start in a restrictive mode, run your test suite and examine any reported CSP failures. The following code snippet demonstrates how you might create a policy for browsers supporting CSP. - +</para> +<code> [source,java] ---- @@ -346,9 +348,9 @@ supporting CSP. if ((browser = chrome.matcher(userAgent)).find()){ int version = Integer.parseInt(browser.group(1)); - if (version >= 25){ + if (version >= 25){ response.addHeader("Content-Security-Policy", policy); - } else if (version < 25 && version > 14){ + } else if (version < 25 ## version > 14){ response.addHeader("X-Webkit-CSP", policy); } else { log.debug("CSP not supported by : " + userAgent); @@ -359,180 +361,181 @@ supporting CSP. ---- - -=== Summary - -Using the CSP in conjunction with the aforementioned mitigation strategies -is a really good defense in depth approach to reduce the likelihood of XSS -attacks. The great thing is that it requires very little effort by web -developers to get a substantial gain in security and therefore it is something -that should be considered as a high priority for those looking to boost the -security of their applications. - -[TIP] -==== -* Validate user input against a whitelist -* Escape user controlled input -* Monitor the use of HTTP parameters for signs of attacks. -* Use CSP to limit the trusted sources of scripts in your web application. -==== - - - -== Session Hijacking - -=== Overview - -A session hijacking attack is when an attacker manages to steal an existing +</code> + </section> + <section> + <title>Summary</title> + <para>Using the CSP in conjunction with the aforementioned mitigation strategies is a really good defense in depth approach to reduce the likelihood of XSS attacks. The great thing is that it requires very little effort by web developers to get a substantial gain in security and therefore it is something that should be considered as a high priority for those looking to boost the security of their applications.</para> +<note><title>TIP</title><para><simplelist> +<member>Validate user input against a whitelist</member> +<member>Escape user controlled input</member> +<member>Monitor the use of HTTP parameters for signs of attacks.</member> +<member>Use CSP to limit the trusted sources of scripts in your web application.</member> +</simplelist></para></note> + </section> + </section> + </section> + <section> + <title>Session Hijacking</title> + <para /> + <section> + <title>Overview</title> + <para>A session hijacking attack is when an attacker manages to steal an existing users session token and impersonate them when talking to the server. Session Hijacking is one possible use of a XSS attack, although sessions may be hijacked by other means. For instance, an attacker may construct a link that pre-emptively sets a users session identifier to a known value which the user then authenticates. Other attacks only require you to be logged into the same network as the attacker and they can simply sniff the network traffic -to access your session token. +to access your session token.</para> -As a result it is essential to ensure all authenticated network traffic is + <para>As a result it is essential to ensure all authenticated network traffic is performed over a secure channel via TLS. Session tokens must be also transmitted -in a secure manner. - -=== Defending against Session Hijacking - - -==== Use non-deterministic session identifiers - -Predictable session identifiers also be used in a session hijacking attack. An attacker +in a secure manner.</para> + </section> + <section> + <title>Defending against Session Hijacking</title> + <para /> + <section> + <title>Use non-deterministic session identifiers</title> + <para>Predictable session identifiers also be used in a session hijacking attack. An attacker only has to guess a valid session identifier to impersonate a different user. Most web frameworks already include a vetted session cookie implementation. It is not recommended that you concoct your own session identification mechanism. It is however -recommended that you verify that the session identifier is suitably random. A useful tool for doing this is called link:http://lcamtuf.coredump.cx/soft/stompy.tgz[Stompy]. -Stompy is a command line entropy verifier for session cookies and XSRF tokens. +recommended that you verify that the session identifier is suitably random. A useful tool for doing this is called <ulink url="http://lcamtuf.coredump.cx/soft/stompy.tgz">Stompy</ulink>.</para> +<para>Stompy is a command line entropy verifier for session cookies and XSRF tokens.</para> +<!-- .TODO - Include stompy usage example? - - -==== Set the HTTP Only flag - -A good protective measure against session hijacking via XSS is to use +--> + </section> + <section> + <title>Set the HTTP Only flag</title> + <para>A good protective measure against session hijacking via XSS is to use a session cookie that cannot be accessed by client side Javascript. This -is achieved by setting the HTTP only flag on the cookie. - -For most web containers you can specify the following option in your -web.xml file. +is achieved by setting the HTTP only flag on the cookie.</para> + <para>For most web containers you can specify the following option in your web.xml file.</para> +<code> [source,xml] ---- ... - <session-config> - <cookie-config> - <http-only>true</http-only> - </cookie-config> - </session-config> + <session-config> + <cookie-config> + <http-only>true</http-only> + </cookie-config> + </session-config> ... ---- +</code> +<para>Of course the +HttpOnly+ flag can be set programmatically when +creating the cookie too.</para> -Of course the +HttpOnly+ flag can be set programmatically when -creating the cookie too. - +<code> [source,java] ---- response.addHeader("Set-Cookie", "foo=bar; HttpOnly;"); ---- - -==== Set the Secure Flag - -Setting the HttpOnly flag will prevent the session cookie from +</code> + </section> + <section> + <title>Set the Secure Flag</title> + <para>Setting the HttpOnly flag will prevent the session cookie from being accessed via client side Javascript, but it doesn't protect the token being transmitted over an insecure channel. Setting the +Secure+ flag on the session cookie will tell the browser not to transmit the -cookie over an insecure channel. +cookie over an insecure channel.</para> -Again, this can be done via the web containers web.xml file. +<para>Again, this can be done via the web containers web.xml file.</para> +<code> [source, xml] ---- ... - <session-config> - <cookie-config> - <http-only>true</http-only> - <secure>true</secure> - </cookie-config> - </session-config> + <session-config> + <cookie-config> + <http-only>true</http-only> + <secure>true</secure> + </cookie-config> + </session-config> ... ---- - -Or programatically. +</code> +<para>Or programatically.</para> +<code> [source,java] ---- response.addHeader("Set-Cookie", "foo=bar; HttpOnly; Secure;"); ---- - -==== Strict transport security (HSTS) - -Taking this a step further, you should ensure that all authenticated +</code> + </section> + <section> + <title>Strict transport security (HSTS)</title> + <para>Taking this a step further, you should ensure that all authenticated network traffic is sent via a TLS connection. Enabling HTTP Strict Transport Security informs compliant browsers to only interact with the web service via a secure HTTPS connection. This protection mechanism is most effective in preventing TLS stripping attacks and helps prevent hijacking by -ensuring a secure connection is always used with the server. +ensuring a secure connection is always used with the server.</para> -To enable HSTS you need only add a Strict-Transport-Security header to + <para>To enable HSTS you need only add a Strict-Transport-Security header to client responses with a +max-age+ value in seconds. The +max-age+ attribute indicates to the browser how long it should honour the HTST -transport request. +transport request.</para> +<code> [source,java] ---- ... response.addHeader("Strict-Transport-Security", "max-age=86400; includeSubdomains"); ... ---- - - -=== Summary - -Using a combination of all these measures will help prevent the incidence of -session hijacking on your site. - -[TIP] -==== -- *DON'T* Use deterministic session identifiers -- *DON'T* Send a session identifier via a HTTP parameter or in the URI -- *DON'T* Allow client side Javascript to have access to the session token. -- *DON'T* Send session tokens over an insecure channel -- *DON'T* Allow authenticated content to travel via HTTP -==== - - -== Click Jacking - -=== Overview - -Click Jacking is when an attacker conceals the true nature of a site using +</code> + </section> + </section> + <section> + <title>Summary</title> + <para>Using a combination of all these measures will help prevent the incidence of +session hijacking on your site.</para> + <note><title>TIP</title><para><simplelist> +<member>*DON'T* Use deterministic session identifiers</member> +<member>*DON'T* Send a session identifier via a HTTP parameter or in the URI</member> +<member>*DON'T* Allow client side Javascript to have access to the session token.</member> +<member>*DON'T* Send session tokens over an insecure channel</member> +<member>*DON'T* Allow authenticated content to travel via HTTP</member> +</simplelist></para></note> + </section> + </section> + <section> + <title>Click Jacking</title> + <para /> + <section> + <title>Overview</title> + <para>Click Jacking is when an attacker conceals the true nature of a site using techniques as cursor spoofing or iframe overlays to trick a user into -clicking on a malicious link to perform unintended actions. - -=== Content Security Policy - -The <<_content_security_policy_csp, XSS section>> introduced +clicking on a malicious link to perform unintended actions.</para> + </section> + <section> + <title>Content Security Policy</title> + <para>The <<_content_security_policy_csp, XSS section>> introduced content security policy, and defining a tight CSP can also help mitigate this class of attack. W3C currently has a link:https://www.w3.org/TR/UISafety/[working draft] -of how CSP may be futher used to mitigate user interface redressing. - -=== X-Frame-Options - -It is common for this class of attack to use iframes to obscure the +of how CSP may be futher used to mitigate user interface redressing.</para> + </section> + <section> + <title>X-Frame-Options</title> + <para>It is common for this class of attack to use iframes to obscure the actual nature of the site. The +X-Frame-Options+ header was introduced by Microsoft in IE8. It allows web application developers to prevent frame based UI redressing. All modern browsers now support this option so it -is worth turning on. +is worth turning on.</para> There are three configuration options for this header. [options="headers"] @@ -606,10 +609,10 @@ Starting from Seam 2.2.1 you can add a CSRF token to user forms as follows. [source, html] ---- -<h:form> - <s:token/> +<h:form> + <s:token/> ... -</h:form> +</h:form> ---- @@ -619,11 +622,11 @@ include the random _csrf_token. [source, html] ---- -<form method="POST" action="/transfer"> +<form method="POST" action="/transfer"> {{ form.hidden_tag() }} - <!-- Define the rest of form fields goes here --> - <button type="submit">Transfer funds</button> -</form> + <!-- Define the rest of form fields goes here --> + <button type="submit">Transfer funds</button> +</form> ---- @@ -773,16 +776,16 @@ session cookie by injecting the EL expression +${cookie["JSESSIONID"].value}+. [source,html] ---- -<!-- +<!-- Consider what happens when any of these values are supplied for the parameter without server side validation. http://example.com/?foo=${cookie["JSESSIONID"].value or http://example.com/?foo=${pageContext.request.getSession().setAttribute("admin", ture)} ---> +--> ... -<h:outputText value="${param.foo}" /> +<h:outputText value="${param.foo}" /> ... ---- @@ -1086,7 +1089,7 @@ import java.nio.file.FileSystems; import java.nio.file.Files; // Restrict read / write to current user only. -Set<PosixFilePermssions> perms = PosixFilePermissions.fromString("rw-------") +Set<PosixFilePermssions> perms = PosixFilePermissions.fromString("rw-------") String prefix = null; // use default String suffix = null; // use default @@ -1143,20 +1146,20 @@ as the SAX parser will process the document on the fly. [source, xml] ---- -<account> - <username>fred</username> - <roles> - <role>staff</role> - </roles> +<account> + <username>fred</username> + <roles> + <role>staff</role> + </roles> - <!-- Consider what would happend if the + <!-- Consider what would happend if the following user controlled input is supplied for nickname. - </nickname><roles><role>admin</role></roles><nickname>freddie - --> - <nickname> + </nickname><roles><role>admin</role></roles><nickname>freddie + --> + <nickname> {{ user_controlled_input }} - </nickname> -</account> + </nickname> +</account> ---- @@ -1203,22 +1206,22 @@ uses entity recursion to expand a small XML document to a huge size. [source, xml] ---- -<!-- billion lolz attack --> -<?xml version="1.0"?> -<!DOCTYPE lolz [ -<!ENTITY lol "lol"> -<!ELEMENT lolz (#PCDATA)> -<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> -<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> -<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> -<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> -<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> -<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> -<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> -<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> -<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> -]> -<lolz>&lol9;</lolz> +<!-- billion lolz attack --> +<?xml version="1.0"?> +<!DOCTYPE lolz [ +<!ENTITY lol "lol"> +<!ELEMENT lolz (#PCDATA)> +<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> +<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> +<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> +<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> +<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> +<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> +<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> +<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> +<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> +]> +<lolz>&lol9;</lolz> ---- To protect against entity expansion in JAXP 1.3 you will need to turn on @@ -1256,11 +1259,11 @@ local or remote content. [source,xml] ---- -<?xml version="1.0" encoding="ISO-8859-1"?> -<!DOCTYPE foo [ - <!ELEMENT foo ANY > - <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> - <foo>&xxe;</foo> +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE foo [ + <!ELEMENT foo ANY > + <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> + <foo>&xxe;</foo> ---- @@ -1349,8 +1352,8 @@ static String safeRedirect(URI baseUrl, String target){ // Assert that normalized URI hostname, port and scheme match if (baseUrl.getHost().equals(redirect.getHost()) - && baseUrl.getPort() == redirect.getPort() - && baseUrl.getScheme().equals(redirect.getScheme())){ + ## baseUrl.getPort() == redirect.getPort() + ## baseUrl.getScheme().equals(redirect.getScheme())){ return redirect.toString(); } @@ -1548,7 +1551,7 @@ it is more of an obstacle for an attack not a prevention mechanism. === Insecure transmission of session data -This has already been touched on in the <<_session_hijacking, session hijacking>> +This has already been touched on in the <<_session_hijacking, session hijacking>> section. To reiterate the main points: * Session data should *ALWAYS* be transmitted over a secure channel. @@ -1704,7 +1707,7 @@ def password_strength_check(form, field): any((sym in string.ascii_uppercase) for c in field.data) and any((sym in string.ascii_lowercase) for c in field.data) and any((sym in string.digits) for c in field.data) and - any((sym in """!@#$%^&*()-_+={}[]\|;:'"/?.>,<`~""".split()) for c in field) + any((sym in """!@#$%^#*()-_+={}[]\|;:'"/?.>,<`~""".split()) for c in field) # Form definition for user registration. @@ -2025,7 +2028,7 @@ def create_person(): ==== XML schema validation -The <<_importance_of_schema_validation,importance of XML schema validation>> +The <<_importance_of_schema_validation,importance of XML schema validation>> has already been touched on in this guide. To summarize you should explicitly validate XML input against a xsd to ensure it is a valid document. @@ -2089,7 +2092,7 @@ as much as possible. * OWASP application verification standard. -== Supporting libraries & tools +== Supporting libraries # tools * OWASP ESAPI * OWASP AntiSammy -- security mailing list security@xxxxxxxxxxxxxxxxxxxxxxx https://admin.fedoraproject.org/mailman/listinfo/security