nsCSPContext.h (10849B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsCSPContext_h___ 8 #define nsCSPContext_h___ 9 10 #include "mozilla/StaticPrefs_security.h" 11 #include "mozilla/dom/CSPViolationData.h" 12 #include "mozilla/dom/SecurityPolicyViolationEvent.h" 13 #include "mozilla/dom/nsCSPUtils.h" 14 #include "nsIChannel.h" 15 #include "nsIChannelEventSink.h" 16 #include "nsIContentSecurityPolicy.h" 17 #include "nsIInterfaceRequestor.h" 18 #include "nsIStreamListener.h" 19 #include "nsIWeakReferenceUtils.h" 20 #include "nsXPCOM.h" 21 22 #define NS_CSPCONTEXT_CONTRACTID "@mozilla.org/cspcontext;1" 23 // 09d9ed1a-e5d4-4004-bfe0-27ceb923d9ac 24 #define NS_CSPCONTEXT_CID \ 25 {0x09d9ed1a, 0xe5d4, 0x4004, {0xbf, 0xe0, 0x27, 0xce, 0xb9, 0x23, 0xd9, 0xac}} 26 27 class nsINetworkInterceptController; 28 class nsIEventTarget; 29 struct ConsoleMsgQueueElem; 30 31 namespace mozilla { 32 namespace dom { 33 class Element; 34 } 35 namespace ipc { 36 class ContentSecurityPolicy; 37 } 38 } // namespace mozilla 39 40 class nsCSPContext : public nsIContentSecurityPolicy { 41 public: 42 NS_DECL_ISUPPORTS 43 NS_DECL_NSICONTENTSECURITYPOLICY 44 NS_DECL_NSISERIALIZABLE 45 46 NS_DEFINE_STATIC_CID_ACCESSOR(NS_CSPCONTEXT_CID) 47 48 protected: 49 virtual ~nsCSPContext(); 50 51 public: 52 nsCSPContext(); 53 54 static bool Equals(nsIContentSecurityPolicy* aCSP, 55 nsIContentSecurityPolicy* aOtherCSP); 56 57 // Init a CSP from a different CSP 58 nsresult InitFromOther(nsCSPContext* otherContext); 59 60 // Used to suppress errors and warnings produced by the parser. 61 // Use this when doing an one-off parsing of the CSP. 62 void SuppressParserLogMessages() { mSuppressParserLogMessages = true; } 63 64 /** 65 * SetRequestContextWithDocument() needs to be called before the 66 * innerWindowID is initialized on the document. Use this function 67 * to call back to flush queued up console messages and initialize 68 * the innerWindowID. Node, If SetRequestContextWithPrincipal() was 69 * called then we do not have a innerWindowID anyway and hence 70 * we can not flush messages to the correct console. 71 */ 72 void flushConsoleMessages(); 73 74 void logToConsole(const char* aName, const nsTArray<nsString>& aParams, 75 const nsACString& aSourceName, const nsAString& aSourceLine, 76 uint32_t aLineNumber, uint32_t aColumnNumber, 77 uint32_t aSeverityFlag); 78 79 /** 80 * Construct SecurityPolicyViolationEventInit structure. 81 * 82 * @param aOriginalUri 83 * The original URI if the blocked content is a redirect, else null 84 * @param aViolatedDirective 85 * the directive that was violated (string). 86 * @param aScriptSample 87 * a sample of the violating inline script 88 * @param aViolationEventInit 89 * The output 90 */ 91 nsresult GatherSecurityPolicyViolationEventData( 92 nsIURI* aOriginalURI, const nsAString& aEffectiveDirective, 93 const mozilla::dom::CSPViolationData& aCSPViolationData, 94 bool aReportSample, 95 mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit); 96 97 nsresult SendReports( 98 const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit, 99 uint32_t aViolatedPolicyIndex); 100 101 nsresult SendReportsToEndpoints( 102 nsAutoString& reportGroup, 103 const mozilla::dom::SecurityPolicyViolationEventInit& 104 aViolationEventInit); 105 106 nsresult SendReportsToURIs( 107 const nsTArray<nsString>& reportURIs, 108 const mozilla::dom::SecurityPolicyViolationEventInit& 109 aViolationEventInit); 110 111 void HandleInternalPageViolation( 112 const mozilla::dom::CSPViolationData& aCSPViolationData, 113 const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit, 114 const nsAString& aViolatedDirectiveNameAndValue); 115 116 nsresult FireViolationEvent( 117 mozilla::dom::Element* aTriggeringElement, 118 nsICSPEventListener* aCSPEventListener, 119 const mozilla::dom::SecurityPolicyViolationEventInit& 120 aViolationEventInit); 121 122 /** 123 * Asynchronously notifies any nsIObservers listening to the CSP violation 124 * topic that a violation occurred. Also triggers report sending and console 125 * logging. All asynchronous on the main thread. 126 * 127 * @param aCSPEventListener Should be null when the violation stems from a 128 * Window. Is required when the violation stems from 129 * a Worker to be potentially notified about the 130 * violation event. 131 * @param aOriginalUri 132 * The original URI if the blocked content is a redirect, else null 133 * @param aViolatedDirectiveName 134 * the directive that was violated (string). 135 * @param aObserverSubject 136 * optional, subject sent to the nsIObservers listening to the CSP 137 * violation topic. 138 */ 139 nsresult AsyncReportViolation( 140 nsICSPEventListener* aCSPEventListener, 141 mozilla::dom::CSPViolationData&& aCSPViolationData, nsIURI* aOriginalURI, 142 const nsAString& aViolatedDirectiveName, 143 const nsAString& aViolatedDirectiveNameAndValue, 144 const nsAString& aObserverSubject, bool aReportSample); 145 146 // Hands off! Don't call this method unless you know what you 147 // are doing. It's only supposed to be called from within 148 // the principal destructor to avoid a tangling pointer. 149 void clearLoadingPrincipal() { mLoadingPrincipal = nullptr; } 150 151 nsWeakPtr GetLoadingContext() { return mLoadingContext; } 152 153 static uint32_t ScriptSampleMaxLength() { 154 return std::max( 155 mozilla::StaticPrefs::security_csp_reporting_script_sample_max_length(), 156 0); 157 } 158 159 void AddIPCPolicy(const mozilla::ipc::ContentSecurityPolicy& aPolicy); 160 void SerializePolicies( 161 nsTArray<mozilla::ipc::ContentSecurityPolicy>& aPolicies); 162 163 static nsCSPContext* Cast(nsIContentSecurityPolicy* aCSP) { 164 return static_cast<nsCSPContext*>(aCSP); 165 } 166 167 [[nodiscard]] nsresult PolicyContainerRead( 168 nsIObjectInputStream* aInputStream); 169 170 private: 171 enum class ForceReportSample { Yes, No }; 172 173 /** 174 * @param aCSPEventListener see `nsCSPContext::AsyncReportViolation`'s csp 175 * event listener argument. 176 */ 177 void LogViolationDetailsUnchecked( 178 nsICSPEventListener* aCSPEventListener, 179 mozilla::dom::CSPViolationData&& aCSPViolationData, 180 const nsAString& aObserverSubject, ForceReportSample aForceReportSample); 181 182 bool ShouldThrottleReport( 183 const mozilla::dom::SecurityPolicyViolationEventInit& 184 aViolationEventInit); 185 186 bool permitsInternal(CSPDirective aDir, 187 mozilla::dom::Element* aTriggeringElement, 188 nsICSPEventListener* aCSPEventListener, 189 nsILoadInfo* aLoadInfo, nsIURI* aContentLocation, 190 nsIURI* aOriginalURIIfRedirect, bool aSpecific, 191 bool aSendViolationReports, 192 bool aSendContentLocationInViolationReports); 193 194 // helper to report inline script/style violations 195 void ReportInlineViolation(CSPDirective aDirective, 196 mozilla::dom::Element* aTriggeringElement, 197 nsICSPEventListener* aCSPEventListener, 198 const nsAString& aNonce, bool aReportSample, 199 const nsAString& aSourceCode, 200 const nsAString& aViolatedDirective, 201 const nsAString& aViolatedDirectiveString, 202 CSPDirective aEffectiveDirective, 203 uint32_t aViolatedPolicyIndex, 204 uint32_t aLineNumber, uint32_t aColumnNumber); 205 206 enum class PolicyDataVersion { 207 Pre136, // Before v136 208 Post136, // v136-137 with bug 1901492 or v138+ with bug 1958259. (This is 209 // the current version) 210 V138_9PreRelease, // v138 Beta/Nightly and v139 Nightly with bug 1942306 211 // and without bug 1958259 212 }; 213 214 nsresult TryReadPolicies(PolicyDataVersion aVersion, 215 nsIObjectInputStream* aStream, uint32_t aNumPolicies, 216 bool aForPolicyContainer); 217 218 [[nodiscard]] nsresult ReadImpl(nsIObjectInputStream* aStream, 219 bool aForPolicyContainer); 220 221 nsCString mReferrer; 222 uint64_t mInnerWindowID; // See `nsPIDOMWindowInner::mWindowID`. 223 bool mSkipAllowInlineStyleCheck; // used to allow Devtools to edit styles 224 // When deserializing an nsCSPContext instance, we initially just keep the 225 // policies unparsed. We will only reconstruct actual CSP policy instances 226 // when there's an attempt to use the CSP. Given a better way to serialize/ 227 // deserialize individual nsCSPPolicy objects, this performance 228 // optimization could go away. 229 nsTArray<mozilla::ipc::ContentSecurityPolicy> mIPCPolicies; 230 nsTArray<nsCSPPolicy*> mPolicies; 231 nsCOMPtr<nsIURI> mSelfURI; 232 nsCOMPtr<nsILoadGroup> mCallingChannelLoadGroup; 233 nsWeakPtr mLoadingContext; 234 nsCOMPtr<nsIPrincipal> mLoadingPrincipal; 235 236 bool mSuppressParserLogMessages = false; 237 238 // helper members used to queue up web console messages till 239 // the windowID becomes available. see flushConsoleMessages() 240 nsTArray<ConsoleMsgQueueElem> mConsoleMsgQueue; 241 bool mQueueUpMessages; 242 nsCOMPtr<nsIEventTarget> mEventTarget; 243 244 mozilla::TimeStamp mSendReportLimitSpanStart; 245 uint32_t mSendReportLimitCount = 1; 246 bool mWarnedAboutTooManyReports = false; 247 RequireTrustedTypesForDirectiveState mRequireTrustedTypesForDirectiveState = 248 RequireTrustedTypesForDirectiveState::NONE; 249 }; 250 251 // Class that listens to violation report transmission and logs errors. 252 class CSPViolationReportListener : public nsIStreamListener { 253 public: 254 NS_DECL_NSISTREAMLISTENER 255 NS_DECL_NSIREQUESTOBSERVER 256 NS_DECL_ISUPPORTS 257 258 public: 259 CSPViolationReportListener(); 260 261 protected: 262 virtual ~CSPViolationReportListener(); 263 }; 264 265 // The POST of the violation report (if it happens) should not follow 266 // redirects, per the spec. hence, we implement an nsIChannelEventSink 267 // with an object so we can tell XHR to abort if a redirect happens. 268 class CSPReportRedirectSink final : public nsIChannelEventSink, 269 public nsIInterfaceRequestor { 270 public: 271 NS_DECL_NSICHANNELEVENTSINK 272 NS_DECL_NSIINTERFACEREQUESTOR 273 NS_DECL_ISUPPORTS 274 275 public: 276 CSPReportRedirectSink(); 277 278 void SetInterceptController( 279 nsINetworkInterceptController* aInterceptController); 280 281 protected: 282 virtual ~CSPReportRedirectSink(); 283 284 private: 285 nsCOMPtr<nsINetworkInterceptController> mInterceptController; 286 }; 287 288 #endif /* nsCSPContext_h___ */