[Django] #26146: django responds to obscure non-standard HTTP verb TRACK?

42 views
Skip to first unread message

Django

unread,
Jan 27, 2016, 12:33:38 PM1/27/16
to django-...@googlegroups.com
#26146: django responds to obscure non-standard HTTP verb TRACK?
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: HTTP handling | Version: 1.8
Severity: Normal | Keywords: trace, track, csrf,
| error, page
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Not sure if this is desired behavior or not, but we had a security audit
on our website. They found that when a TRACK request was made, they hit a
django error page. TRACK seems to be an obscure variant of TRACE unique to
some Microsoft systems. In our case, they were hitting a CSRF failure
page. We don't want people to see anything about us using csrf tokens, or
about the fact that we're using django (or anything else about our
security measures or server environment), so we've just overridden our
CSRF_FAILURE_VIEW to be a simple plain text 401 in our settings when DEBUG
is False.

I can't help but wonder, though... Why does Django respond to this verb in
the first place? It's a non-standard verb. TRACE is all that is needed to
comply with HTTP standards. It really is more of a minor nuisance that it
introduces a (tiny) security issue, with dubious gain. Most developers
have never heard of TRACK and wouldn't know to do something about it.

Thoughts?

--
Ticket URL: <https://code.djangoproject.com/ticket/26146>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jan 27, 2016, 12:41:22 PM1/27/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'

-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution:
Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by timgraham):

* needs_better_patch: => 0
* component: HTTP handling => CSRF
* needs_tests: => 0
* needs_docs: => 0
* stage: Unreviewed => Accepted


Comment:

The issue seems to be this list here:
https://github.com/django/django/blob/31817dd2eb69db54eb559716aae42fe55ada5fea/django/middleware/csrf.py#L127

I agree this doesn't seem ideal.

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:1>

Django

unread,
Jan 27, 2016, 12:56:54 PM1/27/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution:
Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by carljm):

ISTM that the behavior of the CSRF middleware there is fine; it _should_
err on the side of being cautious, and assume that any HTTP verb it
doesn't know for sure is in the "safe" list must be "unsafe" and need CSRF
protection.

The question is whether something _else_ in Django should validate that
the incoming request method is within a list of known methods (and reject
it with 405 METHOD NOT ALLOWED if not?) The OP doesn't clarify what
behavior they expected here.

Anything we would do on that score needs to be opt-in, I think; right now
AFAIK nothing prevents someone from using Django with custom non-standard
HTTP verbs, and we shouldn't just break that.

Personally I'm not sure there's anything here that needs fixing, but I
guess we could add some kind of `ValidateKnownHttpMethod` middleware that
people can use if they want, or something.

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:2>

Django

unread,
Feb 4, 2016, 11:05:56 AM2/4/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution:
Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by hobarrera):

My first thought would be to simply do something like (please take this
more as pseudo-code than actual python):

{{{
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
if passes_check():
ok()
elif request.method in ('PUT', 'POST', 'DELETE'):
reject()
else: # Unknown method that failed the check
return 405 (or maybe 400?)
}}}

Would this be deemed acceptable?

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:3>

Django

unread,
Feb 4, 2016, 11:10:30 AM2/4/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution:
Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by carljm):

I don't see why it's the CSRF middleware's responsibility to return a 405
or 400 in case of an HTTP verb it doesn't recognize. That seems out of
scope for the CSRF middleware. It should exempt known-safe verbs, and
assume everything else needs protection. Which is exactly what it does
now.

If you want unknown verbs to be unconditionally rejected with a 405, just
write a middleware to do that.

I don't see how a new middleware rejecting unknown verbs with 405 would
"clash" with `.dispatch()` any more than having CSRF middleware reject
them with 405 would.

I still don't see anything that needs changing here.

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:4>

Django

unread,
Feb 4, 2016, 11:11:29 AM2/4/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution:
Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by carljm):

I'm inclined to close this ticket; Tim, can you comment on what kind of
change you were envisioning when you accepted it?

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:5>

Django

unread,
Feb 4, 2016, 11:23:11 AM2/4/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution:
Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by timgraham):

I was concerned that you can identify a Django-powered site (presuming it
hasn't customized `settings.CSRF_FAILURE_VIEW`) using something like `curl
-X TRACK https://www.djangoproject.com/` (which returns a "CSRF
verification failed" page), however, now I realized the same issue applies
to `POST` or any other verb so that concern isn't really related this
ticket.

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:6>

Django

unread,
Feb 4, 2016, 11:26:27 AM2/4/16
to django-...@googlegroups.com
#26146: CsrfViewMiddleware responds to any arbitrary HTTP method outside of 'GET',
'HEAD', 'OPTIONS', and 'TRACE'
-------------------------------------+-------------------------------------
Reporter: finetype | Owner: nobody
Type: | Status: closed

Cleanup/optimization |
Component: CSRF | Version: 1.8
Severity: Normal | Resolution: wontfix

Keywords: trace, track, csrf, | Triage Stage: Accepted
error, page |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by carljm):

* status: new => closed
* resolution: => wontfix


Comment:

Yeah, if you want to obscure the fact that you're using Django you need to
customize the CSRF failure view, for sure.

Closing this as wontfix.

--
Ticket URL: <https://code.djangoproject.com/ticket/26146#comment:7>

Reply all
Reply to author
Forward
0 new messages