File indexing completed on 2024-05-05 16:11:43
0001 /* 0002 * Copyright (C) 2007 Apple Inc. All rights reserved. 0003 * 0004 * Redistribution and use in source and binary forms, with or without 0005 * modification, are permitted provided that the following conditions 0006 * are met: 0007 * 0008 * 1. Redistributions of source code must retain the above copyright 0009 * notice, this list of conditions and the following disclaimer. 0010 * 2. Redistributions in binary form must reproduce the above copyright 0011 * notice, this list of conditions and the following disclaimer in the 0012 * documentation and/or other materials provided with the distribution. 0013 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 0014 * its contributors may be used to endorse or promote products derived 0015 * from this software without specific prior written permission. 0016 * 0017 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 0018 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 0019 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 0020 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 0021 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 0022 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 0023 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 0024 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0027 */ 0028 0029 #include "security_origin.h" 0030 0031 #include <wtf/RefPtr.h> 0032 0033 #include <kprotocolinfo.h> 0034 0035 namespace khtml 0036 { 0037 0038 static bool isDefaultPortForProtocol(unsigned short port, const QString &proto) 0039 { 0040 return (port == 80 && proto == QLatin1String("http")) || 0041 (port == 443 && proto == QLatin1String("https")); 0042 } 0043 0044 SecurityOrigin::SecurityOrigin(const QUrl &url) : 0045 m_protocol(url.scheme()) 0046 , m_host(url.host().toLower()) 0047 , m_port(url.port()) 0048 , m_domainWasSetInDOM(false) 0049 , m_isUnique(false) 0050 { 0051 // These protocols do not create security origins; the owner frame provides the origin 0052 if (m_protocol == "about" || m_protocol == "javascript") { 0053 m_protocol = ""; 0054 } 0055 0056 // For edge case URLs that were probably misparsed, make sure that the origin is unique. 0057 if (m_host.isEmpty() && !m_protocol.isEmpty() && KProtocolInfo::protocolClass(m_protocol) == QLatin1String(":internet")) { 0058 m_isUnique = true; 0059 } 0060 0061 // document.domain starts as m_host, but can be set by the DOM. 0062 m_domain = m_host; 0063 0064 if (url.port() == -1 || isDefaultPortForProtocol(m_port, m_protocol)) { 0065 m_port = 0; 0066 } 0067 } 0068 0069 SecurityOrigin::SecurityOrigin(const SecurityOrigin *other) : 0070 m_protocol(other->m_protocol) 0071 , m_host(other->m_host) 0072 , m_domain(other->m_domain) 0073 , m_port(other->m_port) 0074 , m_domainWasSetInDOM(other->m_domainWasSetInDOM) 0075 , m_isUnique(other->m_isUnique) 0076 { 0077 } 0078 0079 bool SecurityOrigin::isEmpty() const 0080 { 0081 return m_protocol.isEmpty(); 0082 } 0083 0084 SecurityOrigin *SecurityOrigin::create(const QUrl &url) 0085 { 0086 if (!url.isValid()) { 0087 return new SecurityOrigin(QUrl()); 0088 } 0089 return new SecurityOrigin(url); 0090 } 0091 0092 SecurityOrigin *SecurityOrigin::createEmpty() 0093 { 0094 return create(QUrl()); 0095 } 0096 0097 void SecurityOrigin::setDomainFromDOM(const QString &newDomain) 0098 { 0099 m_domainWasSetInDOM = true; 0100 m_domain = newDomain.toLower(); 0101 } 0102 0103 bool SecurityOrigin::canAccess(const SecurityOrigin *other) const 0104 { 0105 if (isUnique() || other->isUnique()) { 0106 return false; 0107 } 0108 0109 // Here are two cases where we should permit access: 0110 // 0111 // 1) Neither document has set document.domain. In this case, we insist 0112 // that the scheme, host, and port of the URLs match. 0113 // 0114 // 2) Both documents have set document.domain. In this case, we insist 0115 // that the documents have set document.domain to the same value and 0116 // that the scheme of the URLs match. 0117 // 0118 // This matches the behavior of Firefox 2 and Internet Explorer 6. 0119 // 0120 // Internet Explorer 7 and Opera 9 are more strict in that they require 0121 // the port numbers to match when both pages have document.domain set. 0122 // 0123 // FIXME: Evaluate whether we can tighten this policy to require matched 0124 // port numbers. 0125 // 0126 // Opera 9 allows access when only one page has set document.domain, but 0127 // this is a security vulnerability. 0128 0129 if (m_protocol == other->m_protocol) { 0130 if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) { 0131 if (m_host == other->m_host && m_port == other->m_port) { 0132 return true; 0133 } 0134 } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) { 0135 if (m_domain == other->m_domain) { 0136 return true; 0137 } 0138 } 0139 } 0140 0141 return false; 0142 } 0143 0144 bool SecurityOrigin::canRequest(const QUrl &url) const 0145 { 0146 if (isUnique()) { 0147 return false; 0148 } 0149 0150 WTF::RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); 0151 if (targetOrigin->isUnique()) { 0152 return false; 0153 } 0154 0155 // We call isSameSchemeHostPort here instead of canAccess because we want 0156 // to ignore document.domain effects. 0157 if (isSameSchemeHostPort(targetOrigin.get())) { 0158 return true; 0159 } 0160 0161 return false; 0162 } 0163 0164 bool SecurityOrigin::taintsCanvas(const QUrl &url) const 0165 { 0166 if (canRequest(url)) { 0167 return false; 0168 } 0169 0170 // This function exists because we treat data URLs as having a unique origin, 0171 // contrary to the current (9/19/2009) draft of the HTML5 specification. 0172 // We still want to let folks paint data URLs onto untainted canvases, so 0173 // we special case data URLs below. If we change to match HTML5 w.r.t. 0174 // data URL security, then we can remove this function in favor of 0175 // !canRequest. 0176 if (url.scheme() == QLatin1String("data")) { 0177 return false; 0178 } 0179 0180 return true; 0181 } 0182 0183 void SecurityOrigin::makeUnique() 0184 { 0185 m_isUnique = true; 0186 } 0187 0188 QString SecurityOrigin::toString() const 0189 { 0190 if (isEmpty()) { 0191 return "null"; 0192 } 0193 0194 if (isUnique()) { 0195 return "null"; 0196 } 0197 0198 if (m_protocol == "file") { 0199 return QString("file://"); 0200 } 0201 0202 QString result; 0203 result += m_protocol; 0204 result += "://"; 0205 result += m_host; 0206 0207 if (m_port) { 0208 result += ":"; 0209 result += QString::number(m_port); 0210 } 0211 0212 return result; 0213 } 0214 0215 SecurityOrigin *SecurityOrigin::createFromString(const QString &originString) 0216 { 0217 return SecurityOrigin::create(QUrl(originString)); 0218 } 0219 0220 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin *other) const 0221 { 0222 if (m_host != other->m_host) { 0223 return false; 0224 } 0225 0226 if (m_protocol != other->m_protocol) { 0227 return false; 0228 } 0229 0230 if (m_port != other->m_port) { 0231 return false; 0232 } 0233 0234 return true; 0235 } 0236 0237 } // namespace khtml