menu Chancel's blog
rss_feed
Chancel's blog
有善始者实繁,能克终者盖寡。

跨域请求(CROS)的原理以及解决方案

作者:Chancel Yang, 创建:2019-02-13, 字数:2224, 已阅:620, 最后更新:2024-03-18

跨域是指在不同的域名、协议或端口之间发送 HTTP 请求的限制,它是一种安全机制,旨在防止恶意网站访问或修改其他网站的数据

1. 跨域

1.1. 跨域现象

当浏览器向另一个域名的网站发送请求时,就会发生跨域,例如,如果网站 example.com 尝试从 otherdomain.com 发起请求时,则会发生跨域,跨域会返回以下常见错误

  • HTTP 403 Forbidden
  • HTTP 400 Bad Request
  • HTTP 500 Internal Server Error

1.2. 错误原理

之所以会造成错误,是因为浏览器具备同源策略安全机制

如果两个页面的协议,端口(如果有指定)和域名都相同,则称两个页面具有相同的源

同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互,用于隔离潜在恶意文件的重要安全机制

如果没有这个机制,将难以应对以下问题

  • 防止跨站脚本攻击(XSS),例如从电子邮件中访问合法网站同时携带恶意脚本参数,在访问合法网站时向特定恶意网站发起脚本请求,从而造成用户信息泄漏
  • 防止跨站请求伪造(CSRF),例如访问恶意网站,诱骗用户点击合法网站的链接以提交表单,从而向合法网站发送未经授权的请求造成用户信息泄漏

同时,同源策略有助于保护用户隐私,因为它将防止网站跟踪用户在其他网站上的活动

1.3. 如何应对

显然,在现代互联网中,多个域名互相访问是常见操作,为了应对这种情况,浏览器同时也具备CORS(Cross-Origin Resource Sharing)机制

CORS允许网站在不同域之间安全地共享资,它通过使用HTTP头部来指定哪些域可以访问特定资源,从而实现跨域请求,同时这也是W3C组织推荐的一种跨域访问机制,各大主流浏览器都已经支持这种处理方式

2. HTTP请求

跨域请求在浏览器来看分为2种:

  • 标准HTTP请求
  • 非标准HTTP请求

两者的区别是非标准HTTP请求会触发预检查(Options Method)请求,而标准HTTP请求会直接发起跨域请求

2.1. 标准HTTP请求

标准请求如下

  • 请求方法:GET、POST、HEAD
  • Headers包括:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type
  • Content-Type仅限application/x-www-form-urlencoded、multipart/form-data、text/plain

标准HTTP请求会直接发送跨域请求,并在请求头中携带Origin字段,以表明这是一个跨域的请求,服务器端接到请求后,根据自己的跨域规则设置Access-Control-Allow-OriginAccess-Control-Allow-Methods的响应头,来返回验证结果,两者信息一致,浏览器则接收返回的资源内容

2.2. 非标准HTTP请求

大部分情况下,请求都不会是标准HTTP请求,所以需要处理跨域请求

非标准请求,需要先向目标服务器确认是否允许跨域请求,这个过程称之为预检请求

预检请求通常是Options请求,返回3个值:

  • Access-Control-Allow-Origin
  • Access-Control-Request-Method
  • Access-Control-Request-Headers

这三个值分别指示是否允许请求跨域的源域名、允许跨域的请求方法、允许跨域的请求头,浏览器首先判断发起请求的域名是否在源域名列表中,再判断请求方法和请求头符合目标服务器的要求,最后发起跨域请求

3. CROS方案

清楚跨域的原理后,设置允许跨域就比较清晰了,例如可以在Nginx中增加对跨域的支持如下

TEXT
server {
    listen 80;
    server_name your_domain.com;

    location / {
        # *号表示允许从任何域名发起的请求,这里为演示方便,通常不这么写
        add_header Access-Control-Allow-Origin *;
        # 支持哪些跨域方法
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
        # 支持跨域的headers
        add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept";

        # 其他配置
    }
}

4. 尾语

除了CROS外,还能看到有前端技术JSONP支持跨域请求,它利用了这样一个事实:浏览器不会对script标签施加同源策略限制

JSONP不推荐用于新的 Web 应用程序,现代浏览器已经支持跨域资源共享 (CORS),它是一种更安全、更灵活的方法


[[replyMessage== null?"发表评论":"发表评论 @ " + replyMessage.m_author]]

account_circle
email
web_asset
textsms

评论列表([[messageResponse.total]])

还没有可以显示的留言...
[[messageItem.m_author]] [[messageItem.m_author]]
[[messageItem.create_time]]
[[getEnviron(messageItem.m_environ)]]
[[subMessage.m_author]] [[subMessage.m_author]] @ [[subMessage.parent_message.m_author]] [[subMessage.parent_message.m_author]]
[[subMessage.create_time]]
[[getEnviron(messageItem.m_environ)]]