Skip to content

Commit 04316d3

Browse files
Update qhelp
1 parent 7eabed6 commit 04316d3

File tree

6 files changed

+102
-8
lines changed

6 files changed

+102
-8
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>Cookies without the <code>HttpOnly</code> flag set are accessible to JavaScript running in the same origin.
8+
In case of a Cross-Site Scripting (XSS) vulnerability, the cookie can be stolen by a malicious script.
9+
If a cookie does not need to be accessed directly by client-side JS, the <code>HttpOnly</code> flag should be set.</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>Set <code>httponly</code> to <code>True</code>, or add <code>; HttpOnly;</code> to the cookie's raw header value, to ensure that the cookie is not accessible via JavaScript.</p>
14+
</recommendation>
15+
16+
<example>
17+
<p>In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.</p>
18+
<sample src="examples/InsecureCookie.py" />
19+
</example>
20+
21+
<references>
22+
<li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500600_cookie-without-httponly-flag-set">Cookie without HttpOnly flag set</a></li>
23+
<li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a>.</li>
24+
</references>
25+
26+
</qhelp>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from flask import Flask, request, make_response, Response
2+
3+
4+
@app.route("/good1")
5+
def good1():
6+
resp = make_response()
7+
resp.set_cookie("name", value="value", secure=True, httponly=True, samesite='Strict') # GOOD: Attributes are securely set
8+
return resp
9+
10+
11+
@app.route("/good2")
12+
def good2():
13+
resp = make_response()
14+
resp.headers['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Strict" # GOOD: Attributes are securely set
15+
return resp
16+
17+
@app.route("/bad1")
18+
def bad1():
19+
resp = make_response()
20+
resp.set_cookie("name", value="value", samesite='None') # BAD: the SameSite attribute is set to 'None' and the 'Secure' and 'HttpOnly' attributes are set to False by default.
21+
return resp
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>Cookies with the <code>SameSite</code> attribute set to <code>'None'</code> will be sent with cross-origin requests.
8+
This can sometimes allow for Cross-Site Request Forgery (CSRF) attacks, in which a third-party site could perform actions on behalf of a user.</p>
9+
</overview>
10+
11+
<recommendation>
12+
<p>Set the <code>samesite</code> to <code>Lax</code> or <code>Strict</code>, or add <code>; SameSite=Lax;</code>, or
13+
<code>; SameSite=Strict;</code> to the cookie's raw header value. The default value in most cases is <code>Lax</code>.</p>
14+
</recommendation>
15+
16+
<example>
17+
<p>In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.</p>
18+
<sample src="examples/InsecureCookie.py" />
19+
</example>
20+
21+
<references>
22+
<li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a>.</li>
23+
<li>OWASP: <a href="https://owasp.org/www-community/SameSite">SameSite</a>.</li>
24+
</references>
25+
26+
</qhelp>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from flask import Flask, request, make_response, Response
2+
3+
4+
@app.route("/good1")
5+
def good1():
6+
resp = make_response()
7+
resp.set_cookie("name", value="value", secure=True, httponly=True, samesite='Strict') # GOOD: Attributes are securely set
8+
return resp
9+
10+
11+
@app.route("/good2")
12+
def good2():
13+
resp = make_response()
14+
resp.headers['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Strict" # GOOD: Attributes are securely set
15+
return resp
16+
17+
@app.route("/bad1")
18+
def bad1():
19+
resp = make_response()
20+
resp.set_cookie("name", value="value", samesite='None') # BAD: the SameSite attribute is set to 'None' and the 'Secure' and 'HttpOnly' attributes are set to False by default.
21+
return resp

python/ql/src/Security/CWE-614/InsecureCookie.qhelp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,25 @@
44
<qhelp>
55

66
<overview>
7-
<p>Cookies without the <code>Secure</code> flag set may be transmitted using HTTP instead of HTTPS, which leaves them vulnerable to reading by a third party.</p>
8-
<p>Cookies without the <code>HttpOnly</code> flag set are accessible to JavaScript running in the same origin. In case of a Cross-Site Scripting (XSS) vulnerability, the cookie can be stolen by a malicious script.</p>
9-
<p>Cookies with the <code>SameSite</code> attribute set to <code>'None'</code> will be sent with cross-origin requests, which can be controlled by third-party JavaScript code and allow for Cross-Site Request Forgery (CSRF) attacks.</p>
7+
<p>Cookies without the <code>Secure</code> flag set may be transmitted using HTTP instead of HTTPS.
8+
This leaves them vulnerable to being read by a third party attacker. If a sensitive cookie such as a session
9+
key is intercepted this way, it would allow the attacker to perform actions on a user's behalf.</p>
1010
</overview>
1111

1212
<recommendation>
13-
<p>Always set <code>secure</code> to <code>True</code> or add "; Secure;" to the cookie's raw value.</p>
14-
<p>Always set <code>httponly</code> to <code>True</code> or add "; HttpOnly;" to the cookie's raw value.</p>
15-
<p>Always set <code>samesite</code> to <code>Lax</code> or <code>Strict</code>, or add "; SameSite=Lax;", or
16-
"; Samesite=Strict;" to the cookie's raw header value.</p>
13+
<p>Always set <code>secure</code> to <code>True</code>, or add <code>; Secure;</code> to the cookie's raw header value, to ensure SSL is used to transmit the cookie
14+
with encryption.</p>
1715
</recommendation>
1816

1917
<example>
20-
<p>In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the cases marked BAD they are not set.</p>
18+
<p>In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.</p>
2119
<sample src="examples/InsecureCookie.py" />
2220
</example>
2321

2422
<references>
2523
<li>Detectify: <a href="https://support.detectify.com/support/solutions/articles/48001048982-cookie-lack-secure-flag">Cookie lack Secure flag</a>.</li>
2624
<li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500200_tls-cookie-without-secure-flag-set">TLS cookie without secure flag set</a>.</li>
25+
<li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a>.</li>
2726
</references>
2827

2928
</qhelp>

python/ql/src/Security/CWE-614/examples/InsecureCookie.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def good2():
1515
return resp
1616

1717
@app.route("/bad1")
18+
def bad1():
1819
resp = make_response()
1920
resp.set_cookie("name", value="value", samesite='None') # BAD: the SameSite attribute is set to 'None' and the 'Secure' and 'HttpOnly' attributes are set to False by default.
2021
return resp

0 commit comments

Comments
 (0)