解决jax跨域问题
如下代码,我们使用ajax发起一个http请求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$.ajax({
type:'GET',
url:'https://www.baidu.com',
success:function (data,status) {
console.log(status);
console.log(data);
}
});
</script>
</body>
</html>
当我们将上面代码中的url改成百度的url后,再次运行,就会出现以下情况。 这就是跨域问题。 即ajax为了保证安全性,要求发起ajax请求的页面,和接受ajax请求的服务器,应该在同一个域名/地址下。 如果 发起请求的页面 对应的域名(假设为域名A)和接受该请求的服务器的域名(假设为域名B)两者不相同,就认为是依次跨域请求。 ajax默认情况下,不允许进行跨域访问。 上面的代码中,域名A对应的是本地域名,而域名B是百度的域名,两者不相同。就被认为是跨域,进行报错。 在上篇博客中,我们使用ajax请求了一个云服务器,虽然在本地页面访问云服务器也是跨域访问,但上次的云服务器经过了特殊处理,解开了ajax不能跨域的限制。 处理如下: 在服务器代码中配置跨域,就可以允许本地访问该服务器了。
socket构造http请求
HTTP协议也是基于TCP,只不过在TCP的基础之上,按照HTTP约定的格式,构造出一个字符串并发送。我们可以通过Java中的socket来去“拼装”字符串,并发送请求。 代码如下:
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class HttpClient {
private Socket socket;
private String ip;
private int port;
public HttpClient(String ip,int port) throws IOException {
this.ip=ip;
this.port=port;
socket=new Socket(ip,port);
}
public String get(String url) throws IOException {
StringBuilder request=new StringBuilder();
request.append("GET"+url+"HTTP/1.1\n");
request.append("Host:"+ip+":"+port+"\n");
request.append("\n");
OutputStream outputStream=socket.getOutputStream();
outputStream.write(request.toString().getBytes());
InputStream inputStream=socket.getInputStream();
byte[] buffer=new byte[1024*1024];
int n=inputStream.read(buffer);
return new String(buffer,0,n);
}
public String post(String url,String body) throws IOException {
StringBuilder request=new StringBuilder();
request.append("POST"+url+"HTTP/1.1\n");
request.append("Host:"+ip+":"+port+"\n");
request.append("Context-type:text/plain\n");
request.append("Content-Length:"+body.getBytes().length+"\n");
request.append("\n");
request.append(body);
OutputStream outputStream=socket.getOutputStream();
outputStream.write(request.toString().getBytes());
InputStream inputStream=socket.getInputStream();
byte[] buffer=new byte[1024*1024];
int n=inputStream.read(buffer);
return new String(buffer,0,n,"utf-8");
}
public static void main(String[] args) throws IOException {
HttpClient httpClient=new HttpClient("42.192.83.143",8089);
String resp= httpClient.get("/AjaxMockServer/info");
System.out.println(resp);
}
}
HTTPS协议
什么是HTTPS HTTPS 全称(Hypertext Transfer Protocol over Secure Socket Layer ,超文本安全传输协议),HTTPS是通过网络进行安全通信的传输协议,该协议以HTTP协议为基础,引入了一个加密层,使用SSL/TLS来加密数据包。 HTTPS的主要作用是提供对网站服务器的身份认证,来保护数据传输的隐私和完整性。
数据加密相关概念
明文:真正要传输的数据 密文:加密之后的消息 加密:将明文变成密文 解密:将密文变成明文 密钥(yao,四声):在加密和解密的过程中,需要一个中间数据来辅助进行该过程,这样的数据称为密钥
HTTPS的工作过程
为了保证数据 的安全,就需要进行加密,所以在网络传输中不再直接明文传输,而是传输加密后的密文。
加密的方式有很多,但是整体可以分成两大类:对称加密 和 非对称加密
对称加密: 对称加密其实就是 只通过一个密钥,就可以将明文和密文相互转化。
举例:
我们可以使用异或操作,就可以实现一个简单的对称加密。设明文为8888,密钥为1234,二者异或得到密文 9834.密文和密钥二者异或 就可以解密,得到明文 8888
通过对称加密,我们就可以对数据起到保护作用,即使黑客入侵了路由器,也只能得到请求的密文内容。 上面的办法虽然好,但有一个缺陷,那就是密钥如何约定呢?我们只能让客户端先生成一个密钥,然后当客户端和服务器连接的时候,将该密钥传递给服务器,让服务器保存。 但如果黑客在服务器和客户端连接时便截取了密钥,那又如何保证数据的安全呢?我们可以对密钥进行加密,传输密钥的密钥. 但这样就陷入了先有鸡还是先有蛋的问题,一直加密下去是行不通 的,故而进入了非对称加密。
非对称加密:
非对称加密 是通过 一对密钥,使明文和密文相互转化。 这两个密钥,一个叫做公钥 ,一个叫做 私钥 。
通过公钥对明文加密,变成密文。 通过私钥对密文解密,变成明文 也可以反着用 通过私钥对明文加密,变成密文。 通过公钥对密文解密,变成明文。
这里的公钥和私钥,可以类比成现实生活中 的信箱~公钥就像信箱上的锁,私钥就像使这把锁的钥匙
非对称加密缺点: 运行速度非常慢,比对称加密 慢很多
非对称加密流程
服务器将公钥(公开的密钥)直接发送给客户端。客户端得到公钥后,通过公钥将密钥进行加密,再发送给服务器,服务器通过私钥解密获取到密钥。之后再将收到密钥的消息通过密钥加密后发送给客户端,客户端收到后,就是用该密钥通过对称加密的方式与客户端进行数据传输。 总结:
- 服务器和客户端连接,将公钥发送给客户端。
- 客户端在本地生成密钥,然后用公钥加密,发送给服务器。
- 由于中间的网络设备(如路由器等)没有私钥,即使截获了数据,也无法还原出内部的数据,也就没有办法获得对称密钥。
- 服务器通过自己保留的私钥解密,还原出客户端发送的密钥,然后用这个密钥将响应数据加密返回给客户端。
- 后续的客户端和服务器的通信都只用对称加密即可。
引入了非对称加密后,为什么还要继续使用对称加密?? 因为对称加密 对资源的消耗和运行速度都远远低于非对称加密 ,在实际情况中客户端和服务器交互的数据都很大,如果全部使用非对称加密,整体的传输速度就会非常慢。因此我们只需要通过非对称加密让服务器获得密钥即可,之后用对称加密,可以提高传输效率。
仍然存在的问题
客户端如何获取到公钥 ? 如何保证客户端获取到的公钥 是真实可靠的,而不是黑客伪造的??
任何人都可以生成一对 公钥和私钥,不仅服务器可以生成,黑客一样可以自己生成
假设以下场景,黑客入侵了中间网络设备,并自己生成了 一对 公钥pub2 和私钥pri2 .服务器生成了公钥pub1 和私钥pri1 。服务端通过中间设备向服务器请求公钥,服务器返回公钥pub1,被黑客截获,黑客将伪造的公钥pub2发送给客户端。 接下来客户端用pub2 对密钥加密,将密文传输给中间设备,黑客此时就可以用pri2 解密密文,得到真正的密钥,然后继续pub1 加密密文,再发送给服务器,服务器用pri1 解密,也拿到了密钥。这时虽然服务器拿到了密钥,但黑客也神不知鬼不觉的情况下也拿到了密钥。所以之后的数据加密传输,就形同虚设,黑客可以直接获取所有的明文数据。 这也叫中间人攻击 。 那如何解决这个问题?? 为了解决这个问题,引入了证书机制 。
证书机制
在客户端和服务器初次连接时,服务器就给客户端返回一个证书。 这个证书中不仅包含了公钥,也包含了网站的身份信息。
工作流程:
服务器先生成一对公钥和私钥,然后在第三方机构申请证书,然后服务器将公钥放入证书中,将证书发送给客户端。就算黑客入侵了中间设备,获取了证书,由于证书的校验非常严格,黑客很难伪造一个证书,就算伪造了证书,客户端也可以到第三方机构进行验证。因此客户端可以顺利 拿到真正的公钥,之后加密密钥,发送给服务器。由于黑客没有私钥,截获了数据也无法破译。因此服务器就可以顺利的拿到加密的密钥。
这样就保证了非对称加密的安全问题。
这个过程也是SSL/TLS的握手过程
证书内容: 证书可以看成是一个结构化的字符串,里面包含了以下信息:
证书的校验:
- 判断证书的有效期是否过期
- 判断证书发布机构是否可信
- 判断证书是否被篡改(这个判断流程比较复杂,这里不在介绍)
- …
在浏览器中查看证书: chrome浏览器,右上角打开设置,搜索证书,在管理证书页面,点击 受信任的根证书颁发机构中,可以看到当前浏览器中的证书信息。
总结
HTTPS整个工作过程涉及到的密钥有三组 第一组(非对称加密) :用于校验证书是否被篡改. 服务器持有私钥(私钥在注册证书时获得), 客户端持有公 钥(操作系统包含了可信任的 CA 认证机构有哪些, 同时持有对应的公钥). 服务器使用这个私钥对证书的 签名进行加密. 客户端通过这个公钥解密获取到证书的签名, 从而校验证书内容是否是篡改过. 第二组(非对称加密) :用于协商生成对称加密的密钥. 服务器生成这组 私钥-公钥 对, 然后通过证书把公钥 传递给客户端. 然后客户端用这个公钥给生成的对称加密的密钥加密, 传输给服务器, 服务器通过私钥解 密获取到对称加密密钥. 第三组(对称加密) :客户端和服务器后续传输的数据都通过这个对称密钥加密解密.
参考文章: https://leheavengame.com/article/622e001dcbba634f3982e4cb
|