Skip to content

Commit 6ec6dde

Browse files
authored
Avoid inline script execution for injecting CSRF token (#7016)
Scripts with type="application/json" or "text/plain" are not executed, so we can use them to inject dynamic CSRF data, without allowing inline-script execution in Content-Security-Policy.
1 parent f0095b4 commit 6ec6dde

File tree

4 files changed

+13
-12
lines changed

4 files changed

+13
-12
lines changed

rest_framework/static/rest_framework/js/csrf.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function sameOrigin(url) {
3838
!(/^(\/\/|http:|https:).*/.test(url));
3939
}
4040

41+
window.drf = JSON.parse(document.getElementById('drf_csrf').textContent);
4142
var csrftoken = window.drf.csrfToken;
4243

4344
$.ajaxSetup({

rest_framework/templates/rest_framework/admin.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,11 @@ <h4 class="modal-title" id="myModalLabel">{{ error_title }}</h4>
244244
{% endif %}
245245

246246
{% block script %}
247-
<script>
248-
window.drf = {
249-
csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}",
250-
csrfToken: "{{ csrf_token }}"
251-
};
247+
<script type="application/json" id="drf_csrf">
248+
{
249+
"csrfHeaderName": "{{ csrf_header_name|default:'X-CSRFToken' }}",
250+
"csrfToken": "{{ csrf_token }}"
251+
}
252252
</script>
253253
<script src="{% static "rest_framework/js/jquery-3.5.1.min.js" %}"></script>
254254
<script src="{% static "rest_framework/js/ajax-form.js" %}"></script>

rest_framework/templates/rest_framework/base.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ <h1>{{ name }}</h1>
287287
{% endif %}
288288

289289
{% block script %}
290-
<script>
291-
window.drf = {
292-
csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}",
293-
csrfToken: "{% if request %}{{ csrf_token }}{% endif %}"
294-
};
290+
<script type="application/json" id="drf_csrf">
291+
{
292+
"csrfHeaderName": "{{ csrf_header_name|default:'X-CSRFToken' }}",
293+
"csrfToken": "{% if request %}{{ csrf_token }}{% endif %}"
294+
}
295295
</script>
296296
<script src="{% static "rest_framework/js/jquery-3.5.1.min.js" %}"></script>
297297
<script src="{% static "rest_framework/js/ajax-form.js" %}"></script>

tests/test_templates.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
def test_base_template_with_context():
77
context = {'request': True, 'csrf_token': 'TOKEN'}
88
result = render({}, 'rest_framework/base.html', context=context)
9-
assert re.search(r'\bcsrfToken: "TOKEN"', result.content.decode())
9+
assert re.search(r'"csrfToken": "TOKEN"', result.content.decode())
1010

1111

1212
def test_base_template_with_no_context():
1313
# base.html should be renderable with no context,
1414
# so it can be easily extended.
1515
result = render({}, 'rest_framework/base.html')
1616
# note that this response will not include a valid CSRF token
17-
assert re.search(r'\bcsrfToken: ""', result.content.decode())
17+
assert re.search(r'"csrfToken": ""', result.content.decode())

0 commit comments

Comments
 (0)