如下代码,我们使用ajax发起一个http请求。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<script src="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不能跨域的限制。
处理如下:
在服务器代码中配置跨域,就可以允许本地访问该服务器了。
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");
//构造请求头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=new byte[1024*1024];
//n 表示实际读到的字符串
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");
//构造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=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
全称(Hypertext Transfer Protocol over Secure Socket Layer
,超文本安全传输协议),HTTPS是通过网络进行安全通信的传输协议,该协议以HTTP协议为基础,引入了一个加密层,使用SSL/TLS来加密数据包。
HTTPS的主要作用是提供对网站服务器的身份认证,来保护数据传输的隐私和完整性。
明文:真正要传输的数据
密文:加密之后的消息
加密:将明文变成密文
解密:将密文变成明文
密钥(yao,四声):在加密和解密的过程中,需要一个中间数据来辅助进行该过程,这样的数据称为密钥
为了保证数据
的安全,就需要进行加密,所以在网络传输中不再直接明文传输,而是传输加密后的密文。
加密的方式有很多,但是整体可以分成两大类:对称加密
和 非对称加密
对称加密:
对称加密其实就是 只通过一个密钥,就可以将明文和密文相互转化。
举例:
我们可以使用异或操作,就可以实现一个简单的对称加密。设明文为8888,密钥为1234,二者异或得到密文 9834.密文和密钥二者异或 就可以解密,得到明文 8888
通过对称加密,我们就可以对数据起到保护作用,即使黑客入侵了路由器,也只能得到请求的密文内容。
上面的办法虽然好,但有一个缺陷,那就是密钥如何约定呢?我们只能让客户端先生成一个密钥,然后当客户端和服务器连接的时候,将该密钥传递给服务器,让服务器保存。
但如果黑客在服务器和客户端连接时便截取了密钥,那又如何保证数据的安全呢?我们可以对密钥进行加密,传输密钥的密钥.
但这样就陷入了先有鸡还是先有蛋的问题,一直加密下去是行不通 的,故而进入了非对称加密。
非对称加密:
非对称加密 是通过 一对密钥,使明文和密文相互转化。
这两个密钥,一个叫做公钥
,一个叫做 私钥
。
通过公钥对明文加密,变成密文。
通过私钥对密文解密,变成明文
也可以反着用
通过私钥对明文加密,变成密文。
通过公钥对密文解密,变成明文。
这里的公钥和私钥,可以类比成现实生活中 的信箱~公钥就像信箱上的锁,私钥就像使这把锁的钥匙
非对称加密缺点:
运行速度非常慢,比对称加密 慢很多
服务器将公钥(公开的密钥)直接发送给客户端。客户端得到公钥后,通过公钥将密钥进行加密,再发送给服务器,服务器通过私钥解密获取到密钥。之后再将收到密钥的消息通过密钥加密后发送给客户端,客户端收到后,就是用该密钥通过对称加密的方式与客户端进行数据传输。
总结:
引入了非对称加密后,为什么还要继续使用对称加密??
因为对称加密
对资源的消耗和运行速度都远远低于非对称加密
,在实际情况中客户端和服务器交互的数据都很大,如果全部使用非对称加密,整体的传输速度就会非常慢。因此我们只需要通过非对称加密让服务器获得密钥即可,之后用对称加密,可以提高传输效率。
客户端如何获取到公钥
?
如何保证客户端获取到的公钥
是真实可靠的,而不是黑客伪造的??
任何人都可以生成一对 公钥和私钥,不仅服务器可以生成,黑客一样可以自己生成
假设以下场景,黑客入侵了中间网络设备,并自己生成了 一对 公钥pub2
和私钥pri2
.服务器生成了公钥pub1
和私钥pri1
。服务端通过中间设备向服务器请求公钥,服务器返回公钥pub1,被黑客截获,黑客将伪造的公钥pub2发送给客户端。
接下来客户端用pub2
对密钥加密,将密文传输给中间设备,黑客此时就可以用pri2
解密密文,得到真正的密钥,然后继续pub1
加密密文,再发送给服务器,服务器用pri1
解密,也拿到了密钥。这时虽然服务器拿到了密钥,但黑客也神不知鬼不觉的情况下也拿到了密钥。所以之后的数据加密传输,就形同虚设,黑客可以直接获取所有的明文数据。
这也叫中间人攻击
。
那如何解决这个问题??
为了解决这个问题,引入了证书机制
。
在客户端和服务器初次连接时,服务器就给客户端返回一个证书。
这个证书中不仅包含了公钥,也包含了网站的身份信息。
工作流程:
服务器先生成一对公钥和私钥,然后在第三方机构申请证书,然后服务器将公钥放入证书中,将证书发送给客户端。就算黑客入侵了中间设备,获取了证书,由于证书的校验非常严格,黑客很难伪造一个证书,就算伪造了证书,客户端也可以到第三方机构进行验证。因此客户端可以顺利 拿到真正的公钥,之后加密密钥,发送给服务器。由于黑客没有私钥,截获了数据也无法破译。因此服务器就可以顺利的拿到加密的密钥。
这个过程也是SSL/TLS的握手过程
证书内容:
证书可以看成是一个结构化的字符串,里面包含了以下信息:
证书的校验:
在浏览器中查看证书:
chrome浏览器,右上角打开设置,搜索证书,在管理证书页面,点击 受信任的根证书颁发机构中,可以看到当前浏览器中的证书信息。
HTTPS整个工作过程涉及到的密钥有三组
第一组(非对称加密)
:用于校验证书是否被篡改. 服务器持有私钥(私钥在注册证书时获得), 客户端持有公
钥(操作系统包含了可信任的 CA 认证机构有哪些, 同时持有对应的公钥). 服务器使用这个私钥对证书的
签名进行加密. 客户端通过这个公钥解密获取到证书的签名, 从而校验证书内容是否是篡改过.
第二组(非对称加密)
:用于协商生成对称加密的密钥. 服务器生成这组 私钥-公钥 对, 然后通过证书把公钥
传递给客户端. 然后客户端用这个公钥给生成的对称加密的密钥加密, 传输给服务器, 服务器通过私钥解
密获取到对称加密密钥.
第三组(对称加密)
:客户端和服务器后续传输的数据都通过这个对称密钥加密解密.
参考文章:
https://leheavengame.com/article/622e001dcbba634f3982e4cb