Home | History | Annotate | Download | only in page
      1 /*
      2  * Copyright (C) 2008, 2009 Daniel Bates (dbates (at) intudata.com)
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #ifndef XSSAuditor_h
     28 #define XSSAuditor_h
     29 
     30 #include "PlatformString.h"
     31 #include "TextEncoding.h"
     32 
     33 namespace WebCore {
     34 
     35     class Frame;
     36     class ScriptSourceCode;
     37 
     38     // The XSSAuditor class is used to prevent type 1 cross-site scripting
     39     // vulnerabilities (also known as reflected vulnerabilities).
     40     //
     41     // More specifically, the XSSAuditor class decides whether the execution of
     42     // a script is to be allowed or denied based on the content of any
     43     // user-submitted data, including:
     44     //
     45     // * the URL.
     46     // * the HTTP-POST data.
     47     //
     48     // If the source code of a script resembles any user-submitted data then it
     49     // is denied execution.
     50     //
     51     // When you instantiate the XSSAuditor you must specify the Frame of the
     52     // page that you wish to audit.
     53     //
     54     // Bindings
     55     //
     56     // An XSSAuditor is instantiated within the constructor of a
     57     // ScriptController object and passed the Frame the script originated. The
     58     // ScriptController calls back to the XSSAuditor to determine whether a
     59     // JavaScript script is safe to execute before executing it. The following
     60     // methods call into XSSAuditor:
     61     //
     62     // * ScriptController::evaluateInWorld - used to evaluate JavaScript scripts.
     63     // * ScriptController::executeIfJavaScriptURL - used to evaluate JavaScript URLs.
     64     // * ScriptEventListener::createAttributeEventListener - used to create JavaScript event handlers.
     65     // * HTMLBaseElement::process - used to set the document base URL.
     66     // * HTMLTokenizer::parseTag - used to load external JavaScript scripts.
     67     // * FrameLoader::requestObject - used to load <object>/<embed> elements.
     68     //
     69     class XSSAuditor : public Noncopyable {
     70     public:
     71         XSSAuditor(Frame*);
     72         ~XSSAuditor();
     73 
     74         bool isEnabled() const;
     75 
     76         // Determines whether the script should be allowed or denied execution
     77         // based on the content of any user-submitted data.
     78         bool canEvaluate(const String& code) const;
     79 
     80         // Determines whether the JavaScript URL should be allowed or denied execution
     81         // based on the content of any user-submitted data.
     82         bool canEvaluateJavaScriptURL(const String& code) const;
     83 
     84         // Determines whether the event listener should be created based on the
     85         // content of any user-submitted data.
     86         bool canCreateInlineEventListener(const String& functionName, const String& code) const;
     87 
     88         // Determines whether the external script should be loaded based on the
     89         // content of any user-submitted data.
     90         bool canLoadExternalScriptFromSrc(const String& context, const String& url) const;
     91 
     92         // Determines whether object should be loaded based on the content of
     93         // any user-submitted data.
     94         //
     95         // This method is called by FrameLoader::requestObject.
     96         bool canLoadObject(const String& url) const;
     97 
     98         // Determines whether the base URL should be changed based on the content
     99         // of any user-submitted data.
    100         //
    101         // This method is called by HTMLBaseElement::process.
    102         bool canSetBaseElementURL(const String& url) const;
    103 
    104     private:
    105         class CachingURLCanonicalizer
    106         {
    107         public:
    108             CachingURLCanonicalizer() : m_decodeEntities(false), m_decodeURLEscapeSequencesTwice(false) { }
    109             String canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities,
    110                                    bool decodeURLEscapeSequencesTwice);
    111 
    112         private:
    113             // The parameters we were called with last.
    114             String m_inputURL;
    115             TextEncoding m_encoding;
    116             bool m_decodeEntities;
    117             bool m_decodeURLEscapeSequencesTwice;
    118 
    119             // The cached result.
    120             String m_cachedCanonicalizedURL;
    121         };
    122 
    123         struct FindTask {
    124             FindTask()
    125                 : decodeEntities(true)
    126                 , allowRequestIfNoIllegalURICharacters(false)
    127                 , decodeURLEscapeSequencesTwice(false)
    128             {
    129             }
    130 
    131             String context;
    132             String string;
    133             bool decodeEntities;
    134             bool allowRequestIfNoIllegalURICharacters;
    135             bool decodeURLEscapeSequencesTwice;
    136         };
    137 
    138         static String canonicalize(const String&);
    139         static String decodeURL(const String& url, const TextEncoding& encoding, bool decodeEntities,
    140                                 bool decodeURLEscapeSequencesTwice = false);
    141         static String decodeHTMLEntities(const String&, bool leaveUndecodableEntitiesUntouched = true);
    142 
    143         bool isSameOriginResource(const String& url) const;
    144         bool findInRequest(const FindTask&) const;
    145         bool findInRequest(Frame*, const FindTask&) const;
    146 
    147         bool shouldFullPageBlockForXSSProtectionHeader() const;
    148 
    149         // The frame to audit.
    150         Frame* m_frame;
    151 
    152         // A state store to help us avoid canonicalizing the same URL repeated.
    153         mutable CachingURLCanonicalizer m_cache;
    154     };
    155 
    156 } // namespace WebCore
    157 
    158 #endif // XSSAuditor_h
    159