Changeset 37317 in webkit


Ignore:
Timestamp:
Oct 5, 2008 12:12:30 PM (16 years ago)
Author:
abarth@webkit.org
Message:

WebCore:

2008-10-04 Adam Barth <abarth@webkit.org>

Reviewed by Darin Alder.

Attach the Origin header to POST requests to help defend against
cross-site request forgery.

https://bugs.webkit.org/show_bug.cgi?id=20792

Collin Jackson <collinj@webkit.org> also contributed to this patch.

Tests: http/tests/security/originHeader/origin-header-for-data.html

http/tests/security/originHeader/origin-header-for-empty.html
http/tests/security/originHeader/origin-header-for-get.html
http/tests/security/originHeader/origin-header-for-https.html
http/tests/security/originHeader/origin-header-for-post.html

  • bindings/js/JSDOMWindowBase.cpp: (WebCore::createWindow):
  • loader/FrameLoader.cpp: (WebCore::FrameLoader::createWindow): (WebCore::FrameLoader::urlSelected): (WebCore::FrameLoader::submitForm): (WebCore::FrameLoader::outgoingOrigin): (WebCore::FrameLoader::loadURL): (WebCore::FrameLoader::addExtraFieldsToRequest): (WebCore::FrameLoader::loadPostRequest): (WebCore::FrameLoader::loadResourceSynchronously): (WebCore::FrameLoader::loadItem):
  • loader/FrameLoader.h:
  • loader/SubresourceLoader.cpp: (WebCore::SubresourceLoader::create):
  • loader/loader.cpp: (WebCore::Loader::Host::servePendingRequests):
  • platform/SecurityOrigin.cpp: (WebCore::SecurityOrigin::toHTTPOrigin):
  • platform/SecurityOrigin.h:
  • platform/network/ResourceRequestBase.h: (WebCore::ResourceRequestBase::httpOrigin): (WebCore::ResourceRequestBase::setHTTPOrigin): (WebCore::ResourceRequestBase::clearHTTPOrigin):
  • xml/XMLHttpRequest.cpp: (WebCore::XMLHttpRequest::makeSimpleCrossSiteAccessRequest): (WebCore::XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight): (WebCore::XMLHttpRequest::handleAsynchronousPreflightResult): (WebCore::XMLHttpRequest::didReceiveResponsePreflight):

LayoutTests:

2008-10-04 Adam Barth <abarth@webkit.org>

Reviewed by Darin Adler.

Tests for the new Origin header.

https://bugs.webkit.org/show_bug.cgi?id=20792

Collin Jackson <collinj@webkit.org> also contributed to this patch.

  • http/tests/security/originHeader: Added.
  • http/tests/security/originHeader/origin-header-for-data-expected.txt: Added.
  • http/tests/security/originHeader/origin-header-for-data.html: Added.
  • http/tests/security/originHeader/origin-header-for-empty-expected.txt: Added.
  • http/tests/security/originHeader/origin-header-for-empty.html: Added.
  • http/tests/security/originHeader/origin-header-for-get-expected.txt: Added.
  • http/tests/security/originHeader/origin-header-for-get.html: Added.
  • http/tests/security/originHeader/origin-header-for-https-expected.txt: Added.
  • http/tests/security/originHeader/origin-header-for-https.html: Added.
  • http/tests/security/originHeader/origin-header-for-post-expected.txt: Added.
  • http/tests/security/originHeader/origin-header-for-post.html: Added.
  • http/tests/security/originHeader/origin-header-for-xmlhttprequest-expected.txt: Added.
  • http/tests/security/originHeader/origin-header-for-xmlhttprequest.html: Added.
  • http/tests/security/originHeader/resources: Added.
  • http/tests/security/originHeader/resources/origin-header-post-to-http.html: Added.
  • http/tests/security/originHeader/resources/print-origin.cgi: Added.
Location:
trunk
Files:
30 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r37315 r37317  
     12008-10-05  Adam Barth  <abarth@webkit.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        Tests for the new Origin header.
     6
     7        https://bugs.webkit.org/show_bug.cgi?id=20792
     8
     9        Collin Jackson <collinj@webkit.org> also contributed to this patch.
     10
     11        * http/tests/security/originHeader: Added.
     12        * http/tests/security/originHeader/origin-header-for-data-expected.txt: Added.
     13        * http/tests/security/originHeader/origin-header-for-data.html: Added.
     14        * http/tests/security/originHeader/origin-header-for-empty-expected.txt: Added.
     15        * http/tests/security/originHeader/origin-header-for-empty.html: Added.
     16        * http/tests/security/originHeader/origin-header-for-get-expected.txt: Added.
     17        * http/tests/security/originHeader/origin-header-for-get.html: Added.
     18        * http/tests/security/originHeader/origin-header-for-https-expected.txt: Added.
     19        * http/tests/security/originHeader/origin-header-for-https.html: Added.
     20        * http/tests/security/originHeader/origin-header-for-post-expected.txt: Added.
     21        * http/tests/security/originHeader/origin-header-for-post.html: Added.
     22        * http/tests/security/originHeader/origin-header-for-xmlhttprequest-expected.txt: Added.
     23        * http/tests/security/originHeader/origin-header-for-xmlhttprequest.html: Added.
     24        * http/tests/security/originHeader/resources: Added.
     25        * http/tests/security/originHeader/resources/origin-header-post-to-http.html: Added.
     26        * http/tests/security/originHeader/resources/print-origin.cgi: Added.
     27
    1282008-10-05  Oliver Hunt  <oliver@apple.com>
    229
  • trunk/WebCore/ChangeLog

    r37315 r37317  
     12008-10-05  Adam Barth  <abarth@webkit.org>
     2
     3        Reviewed by Darin Alder.
     4
     5        Attach the Origin header to POST requests to help defend against
     6        cross-site request forgery.
     7
     8        https://bugs.webkit.org/show_bug.cgi?id=20792
     9
     10        Collin Jackson <collinj@webkit.org> also contributed to this patch.
     11
     12        Tests: http/tests/security/originHeader/origin-header-for-data.html
     13               http/tests/security/originHeader/origin-header-for-empty.html
     14               http/tests/security/originHeader/origin-header-for-get.html
     15               http/tests/security/originHeader/origin-header-for-https.html
     16               http/tests/security/originHeader/origin-header-for-post.html
     17
     18        * bindings/js/JSDOMWindowBase.cpp:
     19        (WebCore::createWindow):
     20        * loader/FrameLoader.cpp:
     21        (WebCore::FrameLoader::createWindow):
     22        (WebCore::FrameLoader::urlSelected):
     23        (WebCore::FrameLoader::submitForm):
     24        (WebCore::FrameLoader::outgoingOrigin):
     25        (WebCore::FrameLoader::loadURL):
     26        (WebCore::FrameLoader::addExtraFieldsToRequest):
     27        (WebCore::FrameLoader::loadPostRequest):
     28        (WebCore::FrameLoader::loadResourceSynchronously):
     29        (WebCore::FrameLoader::loadItem):
     30        * loader/FrameLoader.h:
     31        * loader/SubresourceLoader.cpp:
     32        (WebCore::SubresourceLoader::create):
     33        * loader/loader.cpp:
     34        (WebCore::Loader::Host::servePendingRequests):
     35        * platform/SecurityOrigin.cpp:
     36        (WebCore::SecurityOrigin::toHTTPOrigin):
     37        * platform/SecurityOrigin.h:
     38        * platform/network/ResourceRequestBase.h:
     39        (WebCore::ResourceRequestBase::httpOrigin):
     40        (WebCore::ResourceRequestBase::setHTTPOrigin):
     41        (WebCore::ResourceRequestBase::clearHTTPOrigin):
     42        * xml/XMLHttpRequest.cpp:
     43        (WebCore::XMLHttpRequest::makeSimpleCrossSiteAccessRequest):
     44        (WebCore::XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight):
     45        (WebCore::XMLHttpRequest::handleAsynchronousPreflightResult):
     46        (WebCore::XMLHttpRequest::didReceiveResponsePreflight):
     47
    1482008-10-04  Oliver Hunt  <oliver@apple.com>
    249
  • trunk/WebCore/bindings/js/JSDOMWindowBase.cpp

    r37257 r37317  
    273273
    274274    request.setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
     275    FrameLoader::addHTTPOriginIfNeeded(request, activeFrame->loader()->outgoingOrigin());
    275276    FrameLoadRequest frameRequest(request, frameName);
    276277
  • trunk/WebCore/loader/FrameLoader.cpp

    r37112 r37317  
    331331    FrameLoadRequest requestWithReferrer = request;
    332332    requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
     333    addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
    333334
    334335    Page* oldPage = m_frame->page();
     
    400401    if (copy.resourceRequest().httpReferrer().isEmpty())
    401402        copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
     403    addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin());
    402404
    403405    loadFrameRequestWithFormAndValues(copy, lockHistory, event, 0, HashMap<String, String>());
     
    575577
    576578    frameRequest.resourceRequest().setURL(u);
     579    addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
    577580
    578581    submitForm(frameRequest, event);
     
    17831786{
    17841787    return m_outgoingReferrer;
     1788}
     1789
     1790String FrameLoader::outgoingOrigin() const
     1791{
     1792    if (m_frame->document())
     1793        return m_frame->document()->securityOrigin()->toHTTPOrigin();
     1794
     1795    return SecurityOrigin::createEmpty()->toHTTPOrigin();
    17851796}
    17861797
     
    21252136   
    21262137    ResourceRequest request(newURL);
    2127     if (!referrer.isEmpty())
     2138    if (!referrer.isEmpty()) {
    21282139        request.setHTTPReferrer(referrer);
     2140        RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
     2141        addHTTPOriginIfNeeded(request, referrerOrigin->toHTTPOrigin());
     2142    }
    21292143    addExtraFieldsToRequest(request, true, event || isFormSubmission);
    21302144    if (newLoadType == FrameLoadTypeReload)
     
    34063420    if (mainResource)
    34073421        request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
     3422
     3423    // Make sure we send the Origin header.
     3424    addHTTPOriginIfNeeded(request, String());
     3425}
     3426
     3427void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
     3428{
     3429    if (!request.httpOrigin().isEmpty())
     3430        return;  // Request already has an Origin header.
     3431
     3432    // Don't send an Origin header for GET or HEAD to avoid privacy issues.
     3433    // For example, if an intranet page has a hyperlink to an external web
     3434    // site, we don't want to include the Origin of the request because it
     3435    // will leak the internal host name. Similar privacy concerns have lead
     3436    // to the widespread suppression of the Referer header at the network
     3437    // layer.
     3438    if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
     3439        return;
     3440
     3441    // For non-GET and non-HEAD methods, always send an Origin header so the
     3442    // server knows we support this feature.
     3443
     3444    if (origin.isEmpty()) {
     3445        // If we don't know what origin header to attach, we attach the value
     3446        // for an empty origin.
     3447        origin = SecurityOrigin::createEmpty()->toHTTPOrigin();
     3448    }
     3449
     3450    request.setHTTPOrigin(origin);
    34083451}
    34093452
     
    34333476    RefPtr<FormData> formData = inRequest.httpBody();
    34343477    const String& contentType = inRequest.httpContentType();
     3478    String origin = inRequest.httpOrigin();
    34353479
    34363480    ResourceRequest workingResourceRequest(url);   
    3437     addExtraFieldsToRequest(workingResourceRequest, true, true);
    34383481
    34393482    if (!referrer.isEmpty())
    34403483        workingResourceRequest.setHTTPReferrer(referrer);
     3484    workingResourceRequest.setHTTPOrigin(origin);
    34413485    workingResourceRequest.setHTTPMethod("POST");
    34423486    workingResourceRequest.setHTTPBody(formData);
    34433487    workingResourceRequest.setHTTPContentType(contentType);
     3488    addExtraFieldsToRequest(workingResourceRequest, true, true);
    34443489
    34453490    NavigationAction action(url, FrameLoadTypeStandard, true, event);
     
    34833528    if (!referrer.isEmpty())
    34843529        initialRequest.setHTTPReferrer(referrer);
     3530    addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
    34853531
    34863532    if (Page* page = m_frame->page())
     
    42944340            ResourceRequest request(itemURL);
    42954341
    4296             addExtraFieldsToRequest(request, true, formData);
    4297 
    42984342            // If this was a repost that failed the page cache, we might try to repost the form.
    42994343            NavigationAction action;
     
    43064350                request.setHTTPBody(formData);
    43074351                request.setHTTPContentType(item->formContentType());
     4352                RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->formReferrer());
     4353                addHTTPOriginIfNeeded(request, securityOrigin->toHTTPOrigin());
    43084354       
    43094355                // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
     
    43464392            }
    43474393
     4394            addExtraFieldsToRequest(request, true, formData);
    43484395            loadWithNavigationAction(request, action, loadType, 0);
    43494396        }
  • trunk/WebCore/loader/FrameLoader.h

    r37112 r37317  
    194194        String referrer() const;
    195195        String outgoingReferrer() const;
     196        String outgoingOrigin() const;
    196197        void loadEmptyDocumentSynchronously();
    197198
     
    278279
    279280        void addExtraFieldsToRequest(ResourceRequest&, bool isMainResource, bool alwaysFromRequest);
     281        static void addHTTPOriginIfNeeded(ResourceRequest&, String origin);
    280282
    281283        FrameLoaderClient* client() const;
  • trunk/WebCore/loader/SubresourceLoader.cpp

    r35435 r37317  
    9494    else if (!request.httpReferrer())
    9595        newRequest.setHTTPReferrer(fl->outgoingReferrer());
     96    FrameLoader::addHTTPOriginIfNeeded(newRequest, fl->outgoingOrigin());
    9697
    9798    // Use the original request's cache policy for two reasons:
  • trunk/WebCore/loader/loader.cpp

    r36132 r37317  
    3737#include "ResourceRequest.h"
    3838#include "ResourceResponse.h"
     39#include "SecurityOrigin.h"
    3940#include "SubresourceLoader.h"
    4041#include <wtf/Assertions.h>
     
    240241            referrer.setPath("/");
    241242        resourceRequest.setHTTPReferrer(referrer.string());
     243        FrameLoader::addHTTPOriginIfNeeded(resourceRequest, docLoader->doc()->securityOrigin()->toHTTPOrigin());
    242244       
    243245        if (resourceIsCacheValidator) {
  • trunk/WebCore/page/SecurityOrigin.cpp

    r37282 r37317  
    221221}
    222222
     223String SecurityOrigin::toHTTPOrigin() const
     224{
     225    String origin = toString();
     226    if (origin.isEmpty())
     227        return "null";
     228
     229    return origin;
     230}
     231
    223232PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString)
    224233{
  • trunk/WebCore/page/SecurityOrigin.h

    r37282 r37317  
    107107        String toString() const;
    108108
     109        // Convert this SecurityOrigin into a string for use in the HTTP Origin
     110        // header. This is similar to toString(), except that the empty
     111        // SecurityOrigin is represented as the string "null".
     112        String toHTTPOrigin() const;
     113
    109114        // Serialize the security origin for storage in the database. This format is
    110115        // deprecated and should be used only for compatibility with old databases;
  • trunk/WebCore/platform/network/ResourceRequestBase.h

    r36108 r37317  
    7979        void clearHTTPReferrer() { m_httpHeaderFields.remove("Referer"); }
    8080       
     81        String httpOrigin() const { return httpHeaderField("Origin"); }
     82        void setHTTPOrigin(const String& httpOrigin) { setHTTPHeaderField("Origin", httpOrigin); }
     83        void clearHTTPOrigin() { m_httpHeaderFields.remove("Origin"); }
     84
    8185        String httpUserAgent() const { return httpHeaderField("User-Agent"); }
    8286        void setHTTPUserAgent(const String& httpUserAgent) { setHTTPHeaderField("User-Agent", httpUserAgent); }
  • trunk/WebCore/xml/XMLHttpRequest.cpp

    r37190 r37317  
    538538}
    539539
    540 String XMLHttpRequest::accessControlOrigin() const
    541 {
    542     String accessControlOrigin = m_doc->securityOrigin()->toString();
    543     if (accessControlOrigin.isEmpty())
    544         return "null";
    545     return accessControlOrigin;
    546 }
    547 
    548540void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
    549541{
     
    557549    request.setHTTPMethod(m_method);
    558550    request.setAllowHTTPCookies(m_includeCredentials);
    559     request.setHTTPHeaderField("Origin", accessControlOrigin());
     551    request.setHTTPOrigin(m_doc->securityOrigin()->toHTTPOrigin());
    560552
    561553    if (m_requestHeaders.size() > 0)
     
    588580void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
    589581{
    590     String origin = accessControlOrigin();
     582    String origin = m_doc->securityOrigin()->toHTTPOrigin();
    591583    KURL url = m_url;
    592584    url.setUser(String());
     
    676668    request.setHTTPMethod(m_method);
    677669    request.setAllowHTTPCookies(m_includeCredentials);
    678     request.setHTTPHeaderField("Origin", accessControlOrigin());
     670    request.setHTTPOrigin(m_doc->securityOrigin()->toHTTPOrigin());
    679671
    680672    if (m_requestHeaders.size() > 0)
     
    12011193        expiryDelta = 5;
    12021194
    1203     appendPreflightResultCacheEntry(accessControlOrigin(), m_url, expiryDelta, m_includeCredentials, methods.release(), headers.release());
     1195    appendPreflightResultCacheEntry(m_doc->securityOrigin()->toHTTPOrigin(), m_url, expiryDelta, m_includeCredentials, methods.release(), headers.release());
    12041196}
    12051197
Note: See TracChangeset for help on using the changeset viewer.