HTTP的特性是无状态无连接,但是我们登录CSDN、哔站这些,为什么自动帮我们登录了?
Cookie
HTTP Cookie(也称为WebCookie、浏览器Cookie或简称Cookie)是服务器发送到用户浏览器并保存在浏览器上的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态、记录用户偏好等。
工作原理
当用户第一次访问网站的时候,服务器会在响应报头里面添加Set-Cookie字段,用于发送到浏览器,让浏览器接受存储。
之后再次访问这个网站,浏览器会自动在其中携带Cookie字段,将之前保存的Cookie信息发送到服务器
分类
会话的内存Cookie:它是存储在内存里面,只要浏览器关闭,跟着就没了
持久的文件Cookie:它是存储在文件里面的,有明确的过期日期,可以跨多个浏览器会话存在。
持久式通常是二进制存储或者使用sqlite存储,因此要看Cookie推荐直接在对应浏览器上查看
安全性
因为是存储在浏览器里面的,安全性不是特别高
用途
用户认证和会话管理(最重要)
跟踪用户行为
缓存用户偏好等
比如在chrome浏览器下,可以直接访问:chrome://settings/cookies
基本格式
Set-Cookie: <name>=<value>
其中 <name> 是 Cookie 的名称,<value> 是 Cookie 的值。
我们编写一个简易的HTTP服务器看看
cpp
#pragma once
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/file.h>
#include<fcntl.h>
#include<string>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<vector>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
using namespace std;
void signalhander(int sig){
kill(-getpgrp(), SIGKILL);
}
class tcpServer{
public:
tcpServer(uint16_t port):_port(port){
_fd = socket(AF_INET,SOCK_STREAM,0);
}
tcpServer(const tcpServer&)=delete;
tcpServer(tcpServer&&)=delete;
tcpServer& operator=(const tcpServer&)=delete;
tcpServer& operator=(tcpServer&&)=delete;
void run(){
uint16_t port = htons(_port);
uint32_t ip;
inet_pton(AF_INET,"0.0.0.0",&ip);
sockaddr_in in;
memset(&in,0,sizeof(in));
in.sin_port=port;
in.sin_family=AF_INET;
in.sin_addr.s_addr = ip;
int reuse = 1;//端口重用
setsockopt(_fd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
int bindret = bind(_fd,(const sockaddr*)&in,sizeof(in));
if(bindret==-1)throw runtime_error("bind error");
int listenRet = listen(_fd,SOMAXCONN);
if(listenRet==-1)throw runtime_error("listen error");
struct sigaction sg;
memset(&sg,0,sizeof(sg));
sg.sa_handler=SIG_IGN;
sigaction(SIGCHLD,&sg,nullptr);
signal(SIGINT,signalhander);
while(true){
sockaddr_in in;
socklen_t len;
int fd = accept(_fd,(sockaddr*)&in,&len);
pid_t id = fork();
if(id ==0){
if(fork()>0){
close(fd);
exit(0);
}
char buffer[4096];
int ret =recv(fd,buffer,sizeof(buffer)-1,0);
if(ret==-1){
if(errno==EAGAIN||errno==EINTR)continue;
throw runtime_error("recv error");
}
else if(ret==0){
cout<<"子进程"<<getpid()<<"的对端关闭连接"<<endl;
exit(0);
}
buffer[ret]=0;
cout<<"子进程"<<getpid()<<"接收到:"<<buffer<<endl;
string sendstr;
sendstr +="HTTP/1.1 200 OK\r\nSet-Cookie: username=DengGJ\r\n\r\nhello world";
send(fd,sendstr.c_str(),sendstr.size(),0);
cout<<"发送"<<sendstr<<endl<<getpid()<<"关闭连接";
close(fd);
exit(0);
}
close(fd);
}
}
private:
uint16_t _port;
int _fd;//监听套接字
vector<int>_fds;
};
我们发现确实有了
后续我们继续访问
发现确实产生了Cookie字段
如果我们要加多个Cookie,我们加上
即可

另外我们还可以加上

时间
第二个是时间格式,传的是过期时间,这就是为什么我们登录的某个网站,过一段时间后需要重新登录。时间格式必须遵循RFC 1123标准,样例Tue, 01 Jan 2030 12:34:56 GMT或者UTC(推荐),(这几个是世界时,并不是我们当地的时间,但是浏览器会自动进行时区的转换)。
路径
然后就是path 这个是让Cookie在指定的路径下生效,如果是/则是全局生效
我们做个测试,我们将username加上path=a/b只有在这个路径下才会传,然后我们试试

我们发现在/下就不会发送username的Cookie了

主机限制
指定哪些主机可以接收该Cookie,了解即可
recure
仅当使用 HTTPS 协议时才发送 Cookie。这有助于防止 Cookie 在不安全的 HTTP 连接中被截获。
HttpOnly
标记 Cookie 为 HttpOnly,意味着该 Cookie 不能被客户端脚本(如JavaScript)访问。这有助于防止跨站脚本攻击(XSS)。
注意事项
每个Cookie属性都以分号(;)和空格)分隔。
名称和值之间使用等号(=)分隔。
如果Cookie的名称或值包含特殊字符(如空格、分号、逗号等),则需要进行URL编码。
Cookie的问题
虽然Cookie使用了HttpOnly、recure这些可以保证一定的安全性,本地存储的也是二进制或者sqlite。但是黑客可以直接把你本地的文件夹直接拷贝了,他不需要看懂你哪个是Cookie,Cookie内容是什么。只要复制到他电脑上,然后浏览器自己会识别。然后就自动登录了。或者对于二进制或者sqlite,也有专门的工具可以识别。所以Cookie不安全
Session
服务器收到用户发送的信息,服务器不会直接用这个信息来做Set-Cookie的数据,而是会存储到服务器里面,然后使用K-V容器来存储,我们生成一个独一无二的K来作为Set-Cookie的随机数。这样浏览器只会得到一个随机数,那么如果客户端的信息被盗取,也盗取不到用户的信息。
所以session也不是绝对安全的。
服务器会用尽手段来保证用户信息安全,例如尽管Cookie被泄露了,但是服务器可以通过地址的变化等信息来识别当前账户是否异常,如果异常,就会将Cookie失效。