HTTP到HTTPS 作者: zorth 时间: 2024-11-20 分类: 默认分类 # HTTP 与 HTTPS:有什么区别 HTTPS 是支持加密和验证的 HTTP。两种协议的唯一区别是HTTPS 使用 TLS (SSL) 来加密普通的 HTTP 请求和响应,并对这些请求和响应进行数字签名。因此,HTTPS 比 HTTP 安全得多。使用 HTTP 的网站的 URL 中带有 `http://`,而使用 HTTPS 的网站则带有 `https://`。 ![1732255490180.png](https://47.116.196.61/i/2024/11/22/67401f0495d7b.png) # 什么是 HTTP HTTP 代表超文本传输协议,它是一种用于通过网络传输数据的协议,或是一种表示信息的规范顺序和语法。通过互联网发送的大多数信息(包括网站内容和 API 调用)都使用 HTTP 协议。HTTP 消息主要有两种:请求和响应。 简单来说,HTTP 请求是遵循 HTTP 协议的一系列文本行。GET 请求可能如下所示: ```json GET /hello.txt HTTP/1.1 User-Agent: curl/7.63.0 libcurl/7.63.0 OpenSSL/1.1.l zlib/1.2.11 Host: www.example.com Accept-Language: en ``` 用户浏览器生成的这部分文本将通过 Internet 发送。而问题在于,它是明文形式发送的,监视连接的任何人都能读取它。(不熟悉 HTTP 协议的人可能觉得此文本难以理解,但任何对协议的命令和语法有基本了解的人都能轻松读懂。) 当用户通过网站或 Web 应用程序提交敏感数据时,这尤其是一个问题。敏感数据可能是密码、信用卡号,或在表单中输入的任何其他数据。而且在 HTTP 中,所有这些数据都以明文形式发送,任何人都能读取。(当用户提交表单时,浏览器会将其转换为 HTTP POST 请求,而不是 HTTP GET请求。) 源站服务器收到 HTTP 请求时,将发送 HTTP 响应,其类似于: ```json HTTP/1.1 200 OK Date: Wed, 30 Jan 2019 12:14:39 GMT Server: Apache Last-Modified: Mon, 28 Jan 2019 11:17:01 GMT Accept-Ranges: bytes Content-Length: 12 Vary: Accept-Encoding Content-Type: text/plain Hello World! ``` 如果网站使用 HTTP 而非 HTTPS,则监视会话的任何人都可以读取所有请求和响应。本质上,恶意行为者可以只读取请求或响应中的文本,就能知道某人正在索取、发送或接收的确切信息。 # 什么是 HTTPS HTTPS 中的 S 代表“安全”。HTTPS 使用 TLS(或 SSL)来加密HTTP 请求和响应,因此在上例中,攻击者看到的不是其文本,而是一堆看似随机的字符。 攻击者不会看到: ```json GET /hello.txt HTTP/1.1 User-Agent: curl/7.63.0 libcurl/7.63.0 OpenSSL/1.1.l zlib/1.2.11 Host: www.example.com Accept-Language: en ``` 而会看到类似如下: ```json t8Fw6T8UV81pQfyhDkhebbz7+oiwldr1j2gHBB3L3RFTRsQCpaSnSBZ78Vme+DpDVJPvZdZUZHpzbbcqmSW1+3xXGsERHg9YDmpYk0VVDiRvw1H5miNieJeJ/FNUjgH0BmVRWII6+T4MnDwmCMZUI/orxP3HGwYCSIvyzS3MpmmSe4iaWKCOHQ== ``` # 在 HTTPS 中,TLS/SSL 如何加密 HTTP 请求和响应 TLS 使用一种称为公钥加密的技术:密钥有两个,即公钥和私钥,其中公钥通过服务器的 SSL 证书与客户端设备共享。当客户端打开与服务器的连接时,这两个设备使用公钥和私钥商定新的密钥(称为会话密钥),以加密它们之间的后续通信。 然后,所有 HTTP 请求和响应都使用这些会话密钥进行加密),使任何截获通信的人都只能看到随机字符串,而不是明文。 有关加密和密钥的工作原理的更多信息,请参阅什么是加密? # HTTPS 如何帮助验证 Web 服务器身份 身份验证是指核实一个人或一台计算机是否是声称的身份。HTTP 中没有身份验证,它基于信任原则。HTTP 的架构师不一定是做出了隐式信任所有 Web 服务器的决定;他们当时除了安全以外还有其他优先事务。但在现代 Internet 上,身份验证是不可或缺的。 就像身份证件能确认一个人的身份一样,私钥可以确认服务器的身份。当客户端打开与源站服务器的连接通道时(例如,当用户导航到网站时),拥有与网站 SSL 证书中公钥匹配的私钥可证明此服务器确实是该网站的合法主机。这可以防止或帮助阻止在没有身份验证时可能发生的多种攻击. 此外,SSL 证书由签发它的证书颁发机构进行数字签名。这可以确认服务器就是它声称的身份。 # 举例 为了更鲜明得展示两者的区别,我们使用抓包工具Wireshark,分别抓取http请求和https请求。 ![http请求.png](https://47.116.196.61/i/2024/11/22/67401e4446047.png) ![https请求.png](https://47.116.196.61/i/2024/11/22/67401e84dd082.png) 我们可以看到,当使用http请求时,我们可以在Wireshark面板看到请求体中的明文信息,当我们使用https请求时,所有的请求体都是加密的。 ![微信图片_20240421104020.jpg](https://47.116.196.61/i/2024/11/20/673d66e182758.jpg) 这两天折腾了图床、博客还有学了会日语。我觉得这种状态挺好的,折腾图床的过程中学习了使用https提供加密的服务,原来可以通过修改nginx的配置来重定向http请求到https。 ```json # HTTP服务器配置(重定向到HTTPS) server { listen 80; server_name your_domain.com; # 替换成你的域名 # 将所有HTTP请求重定向到HTTPS return 301 https://$server_name$request_uri; } # HTTPS服务器配置 server { listen 443 ssl; server_name your_domain.com; # 替换成你的域名 # SSL证书配置 ssl_certificate /path/to/your/certificate.crt; # 替换成你的证书路径 ssl_certificate_key /path/to/your/private.key; # 替换成你的私钥路径 # SSL配置优化 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # SSL会话缓存 ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # HSTS配置(可选) add_header Strict-Transport-Security "max-age=31536000" always; # 网站根目录配置 root /usr/share/nginx/html; index index.html index.htm; location / { try_files $uri $uri/ =404; } } ``` 这个是基础的使用示例,其实部署别人的服务的话,以php为例,还需要做一些处理,对于PHP服务,我们需要在Nginx配置中添加PHP-FPM的相关配置。以下是一个完整的包含PHP支持的HTTPS配置: ```json # HTTP服务器配置(重定向到HTTPS) server { listen 80; server_name your_domain.com; return 301 https://$server_name$request_uri; } # HTTPS服务器配置 server { listen 443 ssl; server_name your_domain.com; # SSL证书配置 ssl_certificate /path/to/your/certificate.crt; ssl_certificate_key /path/to/your/private.key; # SSL配置优化 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # HSTS配置(可选) add_header Strict-Transport-Security "max-age=31536000" always; # 网站根目录 root /var/www/html; # 修改为你的网站目录 index index.php index.html index.htm; # PHP文件处理 location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # PHP-FPM socket路径 # 或者使用TCP方式: # fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; # 安全相关头部 fastcgi_param HTTPS on; } # 隐藏文件访问限制 location ~ /\. { deny all; } # 静态文件缓存设置 location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ { expires 30d; add_header Cache-Control "public, no-transform"; } # 主目录配置 location / { try_files $uri $uri/ /index.php?$query_string; # 支持PHP框架的URL重写 } } ``` 这里还需要确保php-fpm正在运行 ```json # 安装PHP-FPM(以Ubuntu为例) apt-get install php-fpm # CentOS/RHEL系统: yum install php-fpm # 启动PHP-FPM服务 systemctl start php-fpm systemctl enable php-fpm ``` 检查PHP-FPM配置文件(通常在 /etc/php-fpm.d/www.conf 或 /etc/php/7.x/fpm/pool.d/www.conf): ```json ; 确保用户和组设置正确 user = nginx group = nginx ; 如果使用Unix socket listen = /var/run/php-fpm/php-fpm.sock listen.owner = nginx listen.group = nginx listen.mode = 0660 ; 如果使用TCP ; listen = 127.0.0.1:9000 ``` 设置正确的文件权限: ```json # 设置网站目录权限 chown -R nginx:nginx /var/www/html chmod -R 755 /var/www/html ``` 注意:PHP-FPM错误日志(通常在 /var/log/php-fpm/error.log) --- ```json location ~ \.php$ { # ~ \.php$ 是一个正则表达式,匹配所有以.php结尾的文件 # location 块定义了对PHP文件的处理规则 try_files $uri =404; # 检查PHP文件是否存在,如果不存在则返回404错误 # 这是一个安全措施,防止执行不存在的PHP文件 fastcgi_split_path_info ^(.+\.php)(/.+)$; # 分割URL中的路径信息 # 例如:/script.php/extra/info 会被分割成: # $fastcgi_script_name: /script.php # $fastcgi_path_info: /extra/info fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # 指定如何连接到PHP-FPM处理程序 # 这里使用Unix socket方式(更快,推荐在同一服务器上使用) # fastcgi_pass 127.0.0.1:9000; # 另一种连接方式是TCP(如果PHP-FPM在不同服务器上,就用这个) fastcgi_index index.php; # 设置默认的PHP文件名 # 当访问目录时,默认寻找index.php fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 设置PHP脚本的实际文件路径 # $document_root 是网站根目录 # $fastcgi_script_name 是PHP文件名 # 例如:/var/www/html/index.php include fastcgi_params; # 包含Nginx预定义的FastCGI参数 # 这个文件通常在 /etc/nginx/fastcgi_params # 包含了许多必要的环境变量 fastcgi_param HTTPS on; # 告诉PHP脚本当前是HTTPS连接 # 这样PHP可以正确识别安全连接 } ``` 这里有一些实际的例子: 当访问 https://your-site.com/index.php 时: - Nginx 匹配到这是一个 .php 文件 - 检查文件是否存在(try_files) - 如果存在,通过 socket 或 TCP 传递给 PHP-FPM 处理 - PHP-FPM 执行这个文件并返回结果给 Nginx - Nginx 再将结果发送给用户 部署时的问题排查: ```json # 1. 检查PHP-FPM是否运行 systemctl status php-fpm # 2. 检查socket文件是否存在 ls -l /var/run/php-fpm/php-fpm.sock # 3. 检查日志文件权限 ls -l /var/log/php-fpm/error.log # 4. 测试PHP文件权限 ls -l /var/www/html/index.php ``` 标签: none