文章目录
解决jax跨域问题
如下代码,我们使用ajax发起一个http请求。
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>Title</title></head><body><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script><script>//基于jQuery 里面的ajax 来进行使用
$.ajax({//$是jQuery中已经定义好了的一个对象(变量)// jQuery中的所有的api都是$对象的方法
type:'GET',
url:'https://www.baidu.com',
success:function(data,status){//data就是响应的body,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;publicclassHttpClient{private Socket socket;private String ip;privateint port;publicHttpClient(String ip,int port)throws IOException {this.ip=ip;this.port=port;
socket=newSocket(ip,port);}public String get(String url)throws IOException {
StringBuilder request=newStringBuilder();//构造首行
request.append("GET"+url+"HTTP/1.1\n");//构造请求头header
request.append("Host:"+ip+":"+port+"\n");//构造空行
request.append("\n");//GET 请求不需要body
OutputStream outputStream=socket.getOutputStream();//OutputStream 是一个字节流 ,以字节为单位进行写入// 因此需要把StringBuilder 转换成一个字节数组
outputStream.write(request.toString().getBytes());//读取响应
InputStream inputStream=socket.getInputStream();//创建一个1M大小的缓冲区,用来存放响应数据byte[] buffer=newbyte[1024*1024];//n 表示实际读到的字符串int n=inputStream.read(buffer);returnnewString(buffer,0,n);}public String post(String url,String body)throws IOException {
StringBuilder request=newStringBuilder();//构造首行
request.append("POST"+url+"HTTP/1.1\n");//构造header
request.append("Host:"+ip+":"+port+"\n");
request.append("Context-type:text/plain\n");
request.append("Content-Length:"+body.getBytes().length+"\n");//构造空行
request.append("\n");//构造body
request.append(body);//发送请求
OutputStream outputStream=socket.getOutputStream();
outputStream.write(request.toString().getBytes());//读取响应
InputStream inputStream=socket.getInputStream();byte[] buffer=newbyte[1024*1024];int n=inputStream.read(buffer);returnnewString(buffer,0,n,"utf-8");}publicstaticvoidmain(String[] args)throws IOException {
HttpClient httpClient=newHttpClient("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
版权归原作者 白菜田田 所有, 如有侵权,请联系我们删除。