cookie跨域_PHP解决跨域问题,你会用哪种方法

什么是跨域

跨域,指的是从一个域名去请求另外一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其他域名网站的脚本,是由浏览器的同源策略造成的,是浏览器施加的安全限制。

什么是同源策略

同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

b07b7fce0e09a1c9dcd18f786b877b4e.png

同源策略限制内容有:

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求发送后,结果被浏览器拦截了

但是有三个标签是允许跨域加载资源:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

常见跨域场景有哪些?

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。

常见跨域场景如下图所示:

beb939bf2c2a55f796cbc5bf923e4cc0.png

特别说明两点:

第一:如果是协议和端口造成的跨域问题,那么“前台”是无能为力的。

第二:在跨域问题上,仅仅是通过“URL的首部”来识别,而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。

这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。

你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。

但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

PHP解决跨域问题的方法

跨域的严格一点来说就是只要协议,域名,端口有任何一个的不同,就被当作是跨域。

比如,在实际项目中由于前后端分离当前端需要通过接口向后台发起请求,此时就会出现跨域问题,那么,这类问题需要如何解决呢?

其实php解决跨域问题很简单,只需加上下面的代码就可以了:

header("Access-Control-Allow-Origin:*");

加上这行代码表示允许所有的域名访问,不过为了安全起见,在实际项目中往往会限定只允许固定的几个域名和方法发起的请求。

1、允许单个域名访问

header('Access-Control-Allow-Origin:http://www.startphp.cn');
header('Access-Control-Allow-Methods:POST');    //表示只允许POST请求
header('Access-Control-Allow-Headers:x-requested-with, content-type'); //请求头的限制

2、不限制域名

header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:POST');//表示只允许POST请求
header('Access-Control-Allow-Headers:x-requested-with, content-type');

3、允许多个域名访问

在实际项目中最好指定能跨域访问的域名,增加安全性。可以写在一个公共类里面,封装一个方法调用。

// 设置能访问的域名
static public $originarr = [
   'https://test1.com',
   'https://test2.com',
];

/**
 *  公共方法调用
 */
static public function setheader()
{
   // 获取当前跨域域名
   $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
   if (in_array($origin, self::$originarr)) {
      // 允许 $originarr 数组内的 域名跨域访问
      header('Access-Control-Allow-Origin:' . $origin);
      // 响应类型
      header('Access-Control-Allow-Methods:POST,GET');
      // 带 cookie 的跨域访问
      header('Access-Control-Allow-Credentials: true');
      // 响应头设置
      header('Access-Control-Allow-Headers:x-requested-with,Content-Type,X-CSRF-Token');
   }
}

在php上如何实现

<?php

// 制定允许其他域名访问
header("Access-Control-Allow-Origin:*");

// 响应类型
header('Access-Control-Allow-Methods:POST');

// 响应头设置
header('Access-Control-Allow-Headers:x-requested-with, content-type');

//$callback = isset($_REQUEST['callback']) ? trim($_REQUEST['callback']) : ''; //jsonp回调参数,必需

function getKey($key,$default=""){
    return trim(isset($_REQUEST[$key])?$_REQUEST[$key]:$default);

}

$id = getKey("id");
$conn = mysqli_connect("localhost","root","","test") or die("连接失败");
$conn->query("set names utf8");
$sql = "select * from data where ".$id." is not null";

$result = $conn->query($sql);

$arr = [];
while($row=$result->fetch_assoc()){
    array_push($arr,json_encode($row));

}

$json = json_encode($arr);  //json 数据
print_r($json);

4 代理,这种经常用

比如http://www.startphp.cn/index.html需要调用http://www.mano100.cn/server.php,我们可以这样做,写一个接口http://www.startphp.cn/server.php,由这个接口在后端去调用http://www.mano100.cn/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。

5 Nginx反向代理

使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

修改配置文件nginx.conf,如下:

// proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}

配置修改好后,再重启nginx。

index.html文件访问代理服务器

// index.html
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();

server.js

// server.js
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));
    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });
    res.write(JSON.stringify(params));
    res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');

以上内容希望帮助到大家,更多PHP大厂PDF面试文档,PHP进阶架构视频资料,PHP精彩好文可以关注公众号:PHP开源社区,或者访问:

精华PHP技术文章整理合集——PHP框架篇

精华PHP技术文合集——微服务架构篇

精华PHP技术文合集——分布式架构篇

精华PHP技术文合集——高并发场景篇

精华PHP技术文章整理合集——数据库篇

作者:phper
来源:https://mp.weixin.qq.com/s/HW7bLy3MwDuzARadRTpEPw
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值