汽车电子常见安全机制在 CAN 通讯矩阵或 DBC 文件中，常见到 Checksum 信号和 Rolling Counter 信号。这是由于 CAN 报文信号在汽车 CAN 总线网络传输过程中，由于线阻、阻抗不匹配等原因会导致波形畸变、信号衰减，也会受到外部因素影响。例如外部电磁干扰、黑客恶意攻击篡改等，都可能导致接收方收到的数据与发送方发送的不一致。因此需要一些校验机制来确保 CAN 报文数据是最新且真实可靠的。E2EE2E（End-to-End Protection，端到端保护），一种面向功能安全的通信保护机制，减轻通信过程中出现的数据损坏、丢失、延迟等通信链路错误，确保数据从发送方到接收方的整个逻辑链路中通信正常。CRCCRC（Cyclic Redundancy Check，循环冗余校验），是一种基于多项式除法的查错校验机制。收发双方预先约定一个生成多项式，将待发送的数据帧与生成多项式进行模二除法运算，得到余数。将计算出的 CRC 校验码（余数）附加在数据帧末尾，发送给接收方；接收方对收到的整帧数据用上面约定的生成多项式（除数）做同样的除法运算，验证余数是否为 0，为 0 则表明校验正确，数据传输无误。ChecksumChecksum（校验和），是一种基础、高效的数据完整性校验方法。发送方将数据块按固定字长（通常是字节或字）进行算术累加，取结果的低若干位作为校验值，将校验值附在数据末尾发送；接收方取收到的数据部分重新计算累加和，将算出的 校验值与接收到的校验值直接比较，如果结果一致即说明数据正确。在 IP 协议栈中的 Checksum 计算方式是反码求和后再取反Rolling CounterRolling Counter（滚动计数器）是一种用于监测通信报文时序完整性的机制，确保报文按预期顺序接收。发送方在每个有效报文末尾附加一个按特定规则递增的序号值；接收方通过检查该序号的连续性来判断报文在传输过程中是否发生了丢帧、重复或乱序 。具体判定阈值依据功能安全等级（ASIL）标定，常见逻辑为：连续 5 次出现相同的 Rolling Counter 值，或连续 3 次两帧之间的 Rolling Counter 差值大于 2，则判定发生错误。CRC 与 Checksum 的区别Checksum处于数据段内部，CRC 处于 CRC 段内部。CRC 作为 CAN 协议的一部分，在物理层上解决数据从一个 CAN 节点到另一个 CAN 节点的物理信号差错检测的问题；而 Checksum 是由应用层软件实现，用于校验检查数据是否被正确打包。
# 背景概要 年初 CloudCone 由于 Virtualizor 面板的安全漏洞遭遇入侵，名下部分VPS的数据惨遭清空。丢失的配置和网站文件只能靠自己重建，在重新部署服务器环境的过程中，顺带整理记录下一些Nginx配置的常用配置。 # 基本结构 nginx.conf├── main # 全局配置，定义进程运行参数│ ├── events # 配置事件处理模型与连接方式│ ├── http # HTTP/HTTPS 服务的顶层容器│ │ ├── upstream # 定义后端服务器组，用于负载均衡│ │ ├── upstream│ │ ├── server # 定义虚拟主机，处理特定域名或端口的请求│ │ │ ├── location # 根据 URI 路径匹配，定义请求处理规则│ │ │ ├── location│ │ │ └── location│ │ ├── server│ │ │ ├── location│ │ │ └── location│ │ └── ...│ └── ...└── ... # 模块简介 ## main ==================== Nginx Main 全局块配置 ====================[用户与组]定义 Worker 进程的运行用户/用户组user www www;[工作进程数]定义 Nginx 工作进程的数量推荐设置为 auto, 自动检测 CPU 核心数并启动对应数量的 Worker 进程worker_processes auto;[错误日志]定义错误日志的存储路径和记录级别级别可选：debug | info | notice | warn | error | criterror_log /var/log/nginx/error.log warn;[PID 文件路径]存放 Master 进程 ID 的文件路径pid /run/nginx.pid;[动态模块加载]动态加载编译模块，便于加载编译时未内联的模块load_module modules/ngx_http_headers_more_filter_module.so;[工作进程调度优先级]调整 Worker 进程的 CPU 时间片权重，范围 -20(最高) 到 19(最低)。worker_priority 0; ## **events**块 ==================== Nginx events 块配置 ====================events {# [事件驱动模型] # 指定使用哪种 I/O 多路复用机制，不设置时 Nginx 会自动选择最优模型 # Linux 系统推荐 epoll，FreeBSD 推荐 kqueue。 use epoll; # [单个 Worker 进程的最大并发连接数] # 每个 Worker 可同时处理的最大客户端连接数，包含代理连接。 worker_connections 2048; # [是否允许一次接受所有新连接] # 设为 on 时，Worker 会在收到新连接通知时尽可能多地 accept 连接。 # 高并发短连接场景建议开启。 multi_accept on; # [互斥锁开关 - 惊群问题处理] # 默认 off，新版本已废弃该指令。on 表示多个 Worker 轮流 accept 新连接。 # 当内核支持 EPOLLEXCLUSIVE 或 SO_REUSEPORT 时，建议保持默认 off。 accept_mutex off; # [互斥锁获取失败后的等待时间] # 仅当 accept_mutex 启用时有效，默认 500 毫秒。 # accept_mutex_delay 500ms;} ## http块 ==================== Nginx http 块配置 ====================http {# [MIME 类型文件包含] # 引入外部文件定义文件扩展名到 Content-Type 的映射，确保浏览器正确解析响应。 include /etc/nginx/mime.types; # [默认 MIME 类型] # 当文件扩展名未在 mime.types 中匹配到时，使用的默认类型。 default_type application/octet-stream; # [日志格式定义] # 自定义访问日志的字段与格式，main 为格式名称，便于后续 access_log 引用。 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # [HTTP 级别访问日志] # 记录所有 HTTP 请求，路径与格式可定义。关闭使用 off，或输出到 syslog。 access_log /var/log/nginx/access.log main; # [高效文件传输] # sendfile 启用内核态零拷贝传输，减少上下文切换与数据复制，极大提高静态文件性能。 sendfile on; # TCP_CORK 累积数据包再发送，与 sendfile 配合减少网络包数量。仅在 sendfile on 时有效。 tcp_nopush on; # 禁用 Nagle 算法，小数据包立即发送，降低延迟。适合 keep-alive 连接。 tcp_nodelay on; # [长连接超时] # 客户端 keep-alive 连接的超时时间，超过此时间无请求则断开。 keepalive_timeout 60; # 单个 keep-alive 连接上允许的最大请求数，超过后关闭连接。 keepalive_requests 100; # [客户端相关限制] # 客户端请求体最大大小（如文件上传），0 表示不限制。超出返回 413。 client_max_body_size 10m; # 客户端请求头缓冲区大小，当请求头过大时使用更大的缓冲区。 client_header_buffer_size 1k; # 大请求头的缓冲区数量和大小，超出则返回 414 请求头过长。 large_client_header_buffers 4 8k; # [响应优化] # 隐藏 Nginx 版本号，增强安全性。 server_tokens off; # [Gzip 压缩] gzip on; gzip_comp_level 5; # 压缩等级 1-9，5 是性能与体积的平衡点 gzip_min_length 256; # 仅压缩大于此值的响应 gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; gzip_vary on; # 添加 Vary: Accept-Encoding 头，告知代理服务器内容已压缩，确保浏览器正确缓存压缩文件 gzip_disable "msie6"; # 禁用对 IE6 的压缩 # [上游代理全局超时] # 以下超时通常放置在 server 或 location 中根据需求覆盖。 # 与上游服务器建立连接的超时时间 proxy_connect_timeout 60s; # 从上游服务器读取响应的超时时间 proxy_read_timeout 60s; # 向上游服务器发送请求的超时时间 proxy_send_timeout 60s; # [其他常见全局设置] # 开启目录列表功能（默认 off，生产环境建议关闭） autoindex off; # 配置 server_names_hash 桶大小，当虚拟主机域名较多时增加此值。 server_names_hash_bucket_size 64; # [包含站点配置] # 引入独立文件或目录下的虚拟主机配置，便于管理。 include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*;}
背景众所周知，将任何设备直接暴露于公网都会显著增加受攻击风险，对于家用物联网、NAS这类设备并不适合直接开放到公网上。而在年初飞牛OS就被曝存在路径穿越漏洞，任何暴露于公网的飞牛设备（包括使用fn Connect 内网穿透服务 ）均存在被入侵风险，攻击者可绕过所有身份验证，直接读取任意文件。但对于平时有公网访问需求的情况下，仅开放局域网内访问是不现实的。在各种访问家庭内网的方案中，考虑到安全性与便捷性的平衡，最终采用了动态公网 IPv6 + DDNS + SS 这一方案。方案简介该方案仅开放一个高强度加密的单端口，攻击者无法直接扫描到内网服务，如飞牛 Web 管理页、SMB 等，极大降低了攻击面部署前需确认家庭宽带拥有公网 IPv4 或 IPv6部署过程DDNS0.准备域名如果还没有域名，可以购买一个1.创建专用子用户，添加DNS管理权限以阿里云为例，创建一个RAM用户1，并在权限管理中新增授权，添加DNS管理权限( AliyunDNSFullAccess )，用于更新DNS解析记录2.创建 AccessKey进入对应RAM用户的管理页面，找到 AccessKey 模块开始创建 AccessKey ，获取 AccessKey ID 和 AccessKey Secret3.飞牛配置DDNS进入 系统设置 > 远程访问 > DDNS 模块，新增DDNS选择服务商、输入域名，并将上一步获取到的 AccessKey ID 和 AccessKey Secret 填入完成配置后可点击 测试连接 确认是否配置成功SS服务端部署SS服务直接使用飞牛自带的Docker管理界面部署，傻瓜式操作0.镜像下载从镜像仓库中搜索获取镜像 shadowsocks-libev 并下载1.创建容器到本地镜像中，找到刚下载的镜像文件，点击创建容器实例2.配置容器配置容器端口映射参数配置环境变量，主要关注以下参数{ "SERVER_ADDR":"::", "SERVER_PORT":8910, "PASSWORD":"atfield", "METHOD":"aes-256-gcm", }SERVER_ADDR 配置监听本机IPv6和IPv4地址SERVER_PORT 服务监听端口PASSWORD 加密通信密码METHOD 采用的加密算法将网络模式( network_mode ) 配置为 host勾选“开机自动开启”选项完成以上配置后运行SS客户端配置YAML 配置文件完成服务部署后，该对现有客户端的配置文件进行修改适配以 CFW 配置为例，在现有配置文件添加修改以下内容proxies 添加代理节点，与服务端配置相对应proxies: - name: home type: ss server: ddns.example.com port: "8910" cipher: aes-256-gcm password: atfieldserver 改为DDNS配置的域名proxy-groups 添加策略组proxy-groups: - name: HOME type: select proxies: - homerules 添加规则rules: - IP-CIDR,192.168.1.0/24,HOME,no-resolve将目标 IP 地址为 192.168.1.0/24 的数据包路由到 HOME，该地址需改为 NAS 所在内网网段Bypass Domain/IPNet 配置bypass 检查绕过代理规则移除需要代理的局域网网段配置，确保请求能正常走代理进入 Settings > System Proxy 页面点击 Bypass Domain/IPNet 右边 Edit 小字打开编辑界面根据实际网段修改，确保局域网网段没有出现在 bypass 列表bypass: # - 192.168.* # - 192.168.1.*飞牛OS防火墙启用防火墙进入 系统设置 > 安全性 > 防火墙 模块，启用防火墙在 高级设置 > 局域网 中，勾选 默认允许访问 选项将出入站策略修改为默认拒绝修改入站规则添加入站规则，开放 ss-server 端口的TCP 和 UDP 入站流量，并启用规则将其它所有入站规则都禁用，确保仅开放 ss-server 服务对应的端口验证完成以上配置后，在 CFW 客户端中前往 Proxies 模块，找到对应 home 节点，点击 Check 测试节点是否可用TUN模式以上配置仅对走系统代理的应用生效，因此如网络驱动器映射这类场景是无法访问到 NAS 的。对应此类场景，我们还可以使用工作在网络层的 TUN Mode 来接管系统所有流量，实现全局代理 由于主账号 AccessKey 有资源完全的权限，一旦泄露风险巨大，为了保证权限最小化不建议使用 ↩
如果您看到这篇文章,表示您的 blog 已经安装成功.
python 实现 haversine 公式计算根据经纬度计算两点距离，可以利用半正矢公式来进行计算。半正矢公式半正矢公式是一种根据两点的经度和纬度来确定 大圆距离1 的计算方法，是导航学中的一种基本方法。该公式使用正半矢函数表达，由 $haversin(\theta)=sin^2(\frac{\theta}{2})$ 而来。设球面上任意两点之间的圆心角 $\theta$:$\theta=\frac{d}{r}$$d$ :两点之间的距离$r$ :地球的半径$$ hav(\theta)=hav(\varphi_2-\varphi_1)+cos(\varphi_1)cos(\varphi_2)hav(\lambda_2-\lambda_1) $$公式中：$\varphi$ :纬度(lat.)$\lambda$ :经度(long.)$hav()$ :半正矢函数(haversin)$$ hav(\theta)=sin^2(\frac{\theta}{2})=\frac{1-cos(\theta)}{2} $$变形得到：$$ d=2r\,arcsin\sqrt{sin^2(\frac{\varphi_2-\varphi_1}{2})+cos(\varphi_1)cos(\varphi_2)sin^2(\frac{\lambda_2-\lambda_1}{2})} $$之后我们便可以利用该公式进行地理空间距离计算了实现from math import radians, cos, sin, asin, sqrt, fabs EARTH_RADIUS = 6371 # 地球平均半径：6371km def get_distance_hav(lon0, lat0, lon1, lat1): # 用haversine公式计算球面两点间的距离 lat0 = radians(lat0) lat1 = radians(lat1) lon0 = radians(lon0) lon1 = radians(lon1) dlat = fabs(lat1 - lat0) dlon = fabs(lon1 - lon0) h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlon) distance = 2 * EARTH_RADIUS * asin(sqrt(h)) return distance # 单位：km def hav(theta): s = sin(theta / 2) ** 2 return s利用 GeoPy 库计算Geopy 是一个 Python 库，主要用于处理地理空间数据和地理位置信息。它提供了一系列功能，用于地理编码（地址到经纬度的转换）、反向地理编码（经纬度到地址的转换）、计算两点之间的距离等地理信息处理任务。geopy 的距离计算功能在 geopy.distance中。其计算距离有两种方法：大圆距离(great-circle distance)与测地线距离(geodesic distance)。其区别在于：大圆距离将地球简化为一个半径为 6371.009km的圆球，其计算的距离是球面上两点间的大圆距离；测地线距离使用目前国际通用的方法，用旋转椭球面表示地球，其计算的距离是两点在椭球面上的最短距离。geopy.distance.distance默认使用更精确的 geodesic。安装pip install geopy计算distance以元组 (lat, lon)传入经纬度from geopy import distance # 定义两个坐标点的经纬度 coord0 = (lat0, lon0) coord1 = (lat1, lon1) # distance result = distance.distance(coord0,coord1).km # geodesic result1 = distance.geodesic(coord0,coord1).km # 更改使用的椭球体模型为"Airy (1830)" result2 = distance.geodesic(coord0,coord1,ellipsoid="Airy (1830)").km # 使用 great_circle 距离 result3 = distance.great_circle(coord0,coord1).kmgeodesic有许多流行的椭球体模型，哪一个模型最精确取决于你的点在地球上的位置。默认值是WGS-84椭球体，它是全局最精确的。使用模型名称从 ELLIPSOIDS字典选取值：ELLIPSOIDS = { # model major (km) minor (km) flattening 'WGS-84': (6378.137, 6356.7523142, 1 / 298.257223563), 'GRS-80': (6378.137, 6356.7523141, 1 / 298.257222101), 'Airy (1830)': (6377.563396, 6356.256909, 1 / 299.3249646), 'Intl 1924': (6378.388, 6356.911946, 1 / 297.0), 'Clarke (1880)': (6378.249145, 6356.51486955, 1 / 293.465), 'GRS-67': (6378.1600, 6356.774719, 1 / 298.25) }更多关于GeoPy的使用可以查看GeoPy文档计算结果选取两个坐标点进行计算，使用 %timeit计算函数运行时间lon0, lat0, lon1, lat1 = (113.324548, 23.106413, 113.322552, 23.115056) coord0 = (lat0, lon0) coord1 = (lat1, lon1) result = get_distance_hav(lon0,lat0,lon1,lat1) result1 = distance.geodesic(coord0,coord1).km result2 = distance.great_circle(coord0,coord1).km print("{:<15}{:.6f} km".format("haversine:",result)) print("{:<15}{:.6f} km".format("geodesic:",result1)) print("{:<15}{:.6f} km".format("great_circle:",result2))输出结果：haversine: 0.9825 km geodesic: 0.9788 km great_circle: 0.9825 km平均耗时：haversine: 1.31 µs geodesic: 131 µs great_circle: 8.62 µs根据输出结果可以看出，haversine与geodesic的计算结果的差异较小，但前者的计算时间更短，在不需要高度精确的场景下，牺牲一定精度可以换取更高的效率。 指从球面的一点A出发到达球面上另一点B，所经过的最短路径的长度。 ↩