Bug 68560 - [Qt] HTTP header injection via QWebPage::userAgentForUrl()
Summary: [Qt] HTTP header injection via QWebPage::userAgentForUrl()
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Platform (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Jarred Nicholls
URL:
Keywords: Qt
Depends on:
Blocks:
 
Reported: 2011-09-21 12:45 PDT by Jarred Nicholls
Modified: 2011-12-20 04:56 PST (History)
8 users (show)

See Also:


Attachments
userAgentForUrl stripping (643 bytes, patch)
2011-09-21 12:45 PDT, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.09 KB, patch)
2011-12-19 10:04 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.09 KB, patch)
2011-12-19 10:14 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.12 KB, patch)
2011-12-19 10:45 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.29 KB, patch)
2011-12-19 13:32 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.29 KB, patch)
2011-12-19 13:40 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.28 KB, patch)
2011-12-19 14:04 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff
Patch (3.21 KB, patch)
2011-12-20 03:29 PST, Jarred Nicholls
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jarred Nicholls 2011-09-21 12:45:30 PDT
Created attachment 108210 [details]
userAgentForUrl stripping

This is an interesting issue, that isn't any one particular tier's fault.

When working with PhantomJS (based on QtWebKit), where the user is able to provide their own user agent, we discovered that the user (or attacker?) can set the user agent in such a way to add another HTTP header implicitly to the ResourceRequest:

userAgent = 'My User Agent\nX-My-New-Header: oh noes!';

Which will result in sending the HTTP request w/ headers:

User-Agent: My User Agent
X-My-New-Header: oh noes!

Clearly, this could be problematic.  HTTPHeaderMap doesn't filter the values at all (relying on platform network stack?).  QNetworkRequest clearly just writes the headers onto the stream without a care.  This is either everyone's fault or no one's fault.  While XMLHttpRequest does a validity check of header values (to make sure they don't contain \r or \n) since it's a scriptable API, internal header management does not validate, falling back to the platform's network stack to handle it properly.  Though this is an edge case, QWebPage is offering to the consumer of the QtWebKit API the ability to set the user agent header and doesn't protect it.

Attached is a patch that does the obvious and strips out newline chars to protect this particular scenario, from within WebCore.  But, maybe some handling belongs in QNetwork as well, which would make this a temporary patch.  Or such behavior is acceptable in QNetwork, which means the validation should occur on a higher tier.

Input on this matter is welcomed!
Comment 1 Jesus Sanchez-Palencia 2011-09-21 13:01:54 PDT
(In reply to comment #0)
> Input on this matter is welcomed!

I'm not sure where exactly the "protection" should go, but I agree that we need it. Let's just make sure to have a test covering it as well.

Now that we had this heads-up, is there any other place our API might be prone to injection?!
Comment 2 Jarred Nicholls 2011-09-21 13:09:11 PDT
(In reply to comment #1)
> Now that we had this heads-up, is there any other place our API might be prone to injection?!

Good question; I'll scour the API to see if any relevant issues are present elsewhere.  In the meantime though I will prepare an official patch w/ a test to cover up this one case in particular.  Sound good?
Comment 3 Ademar Reis 2011-09-21 13:56:40 PDT
I fail to see an attack scenario... How could an attacker provide the user-agent? Maybe I'm missing a feature from your PhanonJS, or maybe you don't want to trust the end user at all? Could you please provide a real world attack scenario?

Finally, if this (or any other bug you find) is indeed a security vulnerability, please open a bug against the Security component. This way the bug is kept private while we fix it and give some time to all vendors to fix their applications and distribute the patches to end users (in this case the only vendor would be QtWebKit).

More details about the WebKit security policy here: http://www.webkit.org/security/
Comment 4 Robert Hogan 2011-09-21 14:04:22 PDT
This is an interesting find, but I agree with Ademar it's not a vulnerability. If a client is allowing third-party code to set the UA there isn't much additional leverage to be had from adding a new header. Still worth fixing though.
Comment 5 Jarred Nicholls 2011-09-21 14:10:34 PDT
(In reply to comment #3)
> I fail to see an attack scenario... How could an attacker provide the user-agent? Maybe I'm missing a feature from your PhanonJS, or maybe you don't want to trust the end user at all? Could you please provide a real world attack scenario?
> 
> Finally, if this (or any other bug you find) is indeed a security vulnerability, please open a bug against the Security component. This way the bug is kept private while we fix it and give some time to all vendors to fix their applications and distribute the patches to end users (in this case the only vendor would be QtWebKit).
> 
> More details about the WebKit security policy here: http://www.webkit.org/security/

I consider this more of a straight up bug in handling the result from userAgentFromUrl - not so much a security problem.

My scenario: because PhantomJS exposes a global "phantomjs" variable in the context of a web site (as a tool its often used to scrape web sites), a site could detect its presence and set the user agent overriding some identity headers (cookies, preflight origin w/ CORS? etc.) and who the heck knows what could come next.

Niche, and no big deal.  But, nevertheless, userAgentFromUrl shouldn't return an invalid header value; at least that we can all agree with.
Comment 6 Ariya Hidayat 2011-09-21 14:28:17 PDT
Related PhantomJS comment:

http://code.google.com/p/phantomjs/issues/detail?id=45#c5
Comment 7 Ademar Reis 2011-09-22 06:42:49 PDT
Changing the bug title to clarify this is not a security problem.
Comment 8 Jarred Nicholls 2011-12-19 10:04:41 PST
Created attachment 119879 [details]
Patch
Comment 9 WebKit Review Bot 2011-12-19 10:06:33 PST
Attachment 119879 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 10 Jarred Nicholls 2011-12-19 10:07:33 PST
> Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
> Total errors found: 1 in 3 files

false positive
Comment 11 Early Warning System Bot 2011-12-19 10:10:42 PST
Comment on attachment 119879 [details]
Patch

Attachment 119879 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/10934582
Comment 12 Jarred Nicholls 2011-12-19 10:14:43 PST
Created attachment 119881 [details]
Patch
Comment 13 WebKit Review Bot 2011-12-19 10:17:04 PST
Attachment 119881 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 14 Early Warning System Bot 2011-12-19 10:18:49 PST
Comment on attachment 119881 [details]
Patch

Attachment 119881 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/10928607
Comment 15 Jarred Nicholls 2011-12-19 10:45:13 PST
Created attachment 119884 [details]
Patch
Comment 16 WebKit Review Bot 2011-12-19 10:48:19 PST
Attachment 119884 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 17 Benjamin Poulain 2011-12-19 13:12:22 PST
Comment on attachment 119884 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=119884&action=review

> Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp:739
> +        return m_webFrame->page()->userAgentForUrl(url).replace(QRegExp(QLatin1String("[\n\r]")), QLatin1String(""));

QLatin1String("") -> QLatin1String().
Using QRegExp() is always a bad idea.
Comment 18 Benjamin Poulain 2011-12-19 13:13:28 PST
Comment on attachment 119884 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=119884&action=review

> Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2680
> +    virtual QString userAgentForUrl(const QUrl& url) const
> +    { return QString("My User Agent\nX-New-Http-Header: Oh Noes!"); }

Coding style.

> Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2686
> +    QString userAgent("My User AgentX-New-Http-Header: Oh Noes!");

Make that a static const QLatin1String in CustomUserAgentWebPage?
Comment 19 Jarred Nicholls 2011-12-19 13:32:25 PST
Created attachment 119908 [details]
Patch
Comment 20 WebKit Review Bot 2011-12-19 13:35:41 PST
Attachment 119908 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 21 Early Warning System Bot 2011-12-19 13:36:37 PST
Comment on attachment 119908 [details]
Patch

Attachment 119908 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/10943036
Comment 22 Jarred Nicholls 2011-12-19 13:37:32 PST
(In reply to comment #21)
> (From update of attachment 119908 [details])
> Attachment 119908 [details] did not pass qt-ews (qt):
> Output: http://queues.webkit.org/results/10943036

lol, thanks Benjamin ;-P  I love cowboying patches...
Comment 23 Jarred Nicholls 2011-12-19 13:40:24 PST
Created attachment 119911 [details]
Patch
Comment 24 WebKit Review Bot 2011-12-19 13:42:26 PST
Attachment 119911 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 25 Jarred Nicholls 2011-12-19 14:04:02 PST
Created attachment 119916 [details]
Patch
Comment 26 WebKit Review Bot 2011-12-19 14:08:06 PST
Attachment 119916 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 27 Benjamin Poulain 2011-12-19 14:48:11 PST
Comment on attachment 119916 [details]
Patch

Actually, I know think this is incorrect. A end of line is valid in a header with a continuation (http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 ). You might decide not to handle this case in Qt
Comment 28 Benjamin Poulain 2011-12-19 14:48:12 PST
Comment on attachment 119916 [details]
Patch

Actually, I know think this is incorrect. A end of line is valid in a header with a continuation (http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 ). You might decide not to handle this case in Qt
Comment 29 Jarred Nicholls 2011-12-19 15:01:09 PST
(In reply to comment #28)
> (From update of attachment 119916 [details])
> Actually, I know think this is incorrect. A end of line is valid in a header with a continuation (http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 ). You might decide not to handle this case in Qt

We can do a white space check after a crlf before deciding to strip.  I'm dropping this bug for now, someone can choose to merge this as-is, enhance it per the rfc, or forget about it.  For user agent though I can say that it's reasonable to forget about line comtinuations...
Comment 30 Simon Hausmann 2011-12-20 00:28:20 PST
Comment on attachment 119916 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=119916&action=review

I think that's a very good solution to the problem. I think this can be written more efficiently though and there's a style nitpick :)

> Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp:739
> +        return m_webFrame->page()->userAgentForUrl(url).replace(QLatin1String("\n"), QString()).replace(QLatin1String("\r"), QString());

I think it is better to use remove() instead of replace():

    return m_webFrame->page()->userAgentForUrl(url).remove(QLatin1Char('\n')).remove(QLatin1Char('\r'));

I think in the common case of _no_ newlines/linefeeds being present, the simple iteration that QString::remove(QChar) does is faster
than creating temporary QStrings and firing up the QStringMatcher machinery.
Comment 31 Simon Hausmann 2011-12-20 00:29:43 PST
(In reply to comment #29)
> (In reply to comment #28)
> > (From update of attachment 119916 [details] [details])
> > Actually, I know think this is incorrect. A end of line is valid in a header with a continuation (http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 ). You might decide not to handle this case in Qt
> 
> We can do a white space check after a crlf before deciding to strip.  I'm dropping this bug for now, someone can choose to merge this as-is, enhance it per the rfc, or forget about it.  For user agent though I can say that it's reasonable to forget about line comtinuations...

Yeah, I'm inclined to agree. Let's not worry about continuations while at the same time the fix to this problem is simple enough that we could put it straight into the library :)
Comment 32 Jarred Nicholls 2011-12-20 03:29:53 PST
Created attachment 120003 [details]
Patch

Sounds good Simon, remove() for the win.  New patch...
Comment 33 WebKit Review Bot 2011-12-20 03:31:20 PST
Attachment 120003 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit/qt/ChangeLog', u'Source/WebK..." exit_code: 1

Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 34 Simon Hausmann 2011-12-20 03:41:19 PST
Comment on attachment 120003 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=120003&action=review

>> Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677
>> +{
> 
> This { should be at the end of the previous line  [whitespace/braces] [4]

Style queue is right here.... ;) Want to fix it when landing?
Comment 35 Jarred Nicholls 2011-12-20 03:43:13 PST
(In reply to comment #34)
> (From update of attachment 120003 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=120003&action=review
> 
> >> Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677
> >> +{
> > 
> > This { should be at the end of the previous line  [whitespace/braces] [4]
> 
> Style queue is right here.... ;) Want to fix it when landing?

I can but it's consistent with *all* of the other test classes in there; I purposefully ignored the style checker on this one.  I'd rather stay consistent to the file.  Let me know and I'll do one or the other before landing.
Comment 36 Simon Hausmann 2011-12-20 03:45:57 PST
(In reply to comment #35)
> (In reply to comment #34)
> > (From update of attachment 120003 [details] [details])
> > View in context: https://bugs.webkit.org/attachment.cgi?id=120003&action=review
> > 
> > >> Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp:2677
> > >> +{
> > > 
> > > This { should be at the end of the previous line  [whitespace/braces] [4]
> > 
> > Style queue is right here.... ;) Want to fix it when landing?
> 
> I can but it's consistent with *all* of the other test classes in there; I purposefully ignored the style checker on this one.  I'd rather stay consistent to the file.  Let me know and I'll do one or the other before landing.

That's fine with me, too :)
Comment 37 Simon Hausmann 2011-12-20 03:46:19 PST
Comment on attachment 120003 [details]
Patch

In that case, let's give it a go :)
Comment 38 Jarred Nicholls 2011-12-20 03:47:15 PST
(In reply to comment #37)
> (From update of attachment 120003 [details])
> In that case, let's give it a go :)

Ok cool :)  Thanks for the review.
Comment 39 WebKit Review Bot 2011-12-20 04:56:24 PST
Comment on attachment 120003 [details]
Patch

Clearing flags on attachment: 120003

Committed r103320: <http://trac.webkit.org/changeset/103320>
Comment 40 WebKit Review Bot 2011-12-20 04:56:30 PST
All reviewed patches have been landed.  Closing bug.