4、接口安全设计:API认证机制、数据加密与防篡改防重放
接口安全这事儿,说实话,是MES集成里最容易被人忽视,但一出事就让你吃不了兜着走的地方。我见过太多项目,业务逻辑跑得飞起,安全方面却像个筛子。今天咱们就把这块硬骨头啃下来。
4.1 API认证机制:谁在敲门?
认证说白了就是确认身份。你想想看,一个MES接口要是谁都能调,那产线上的数据不就乱套了?我习惯把认证机制分成三个层次来讲。
4.1.1 Basic Auth:最简单的,也是最危险的
Basic Auth就是把用户名和密码用Base64编码一下,塞到HTTP头里。嗯,这里要注意——Base64不是加密,它只是编码。我在项目中遇到过有人拿它当加密用,结果抓个包就能看到明文密码。
// 一个典型的Basic Auth请求头
Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=
看到没?那串乱码随便找个在线工具就能解码。所以我的建议是:除非你是在搭测试环境,否则别碰Basic Auth。
4.1.2 Token认证:更灵活的方式
Token认证的思路是:你先用账号密码换一个临时令牌,后面拿着令牌去调接口。这样密码就不用每次都传了。
我曾经帮一个客户排查过问题,他们的Token有效期设了30天。结果一个离职员工的Token还能用,差点造成数据泄露。所以Token一定要设有效期,我一般建议不超过24小时。
// 获取Token的请求
POST /api/auth/login
{
"username": "admin",
"password": "your_password"
}
// 返回的Token
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 86400
}
// 后续请求带上Token
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
4.1.3 JWT:自包含的令牌
JWT(JSON Web Token)是我个人最常用的方案。它把用户信息直接编码在Token里,服务端不用查数据库就能知道你是谁。说白了,JWT就是一个带签名的JSON数据包。
举个例子,一个典型的JWT长这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
这里有个坑:JWT的Payload是Base64编码,不是加密。所以千万别把密码、身份证号这类敏感信息放进去。我见过有人把数据库连接串放JWT里,想想都后怕。
4.2 数据加密:TLS/SSL,你的数据保险箱
认证搞定了,但数据在传输过程中还是裸奔的。这时候就需要TLS/SSL上场了。说白了,就是在客户端和服务端之间建一条加密隧道。
我记得有一次帮一个工厂做MES升级,发现他们的PLC数据直接明文传输。我说这不行啊,万一有人截获了数据,修改个生产参数,整条线都得废。后来强制上了TLS 1.2,才算安心。
配置TLS其实不复杂,核心就是证书。我习惯用Let's Encrypt的免费证书,或者企业内部自建CA。关键是要把证书链配全,别漏了中间证书。
# Nginx配置示例
server {
listen 443 ssl;
server_name api.mes.example.com;
ssl_certificate /etc/ssl/certs/mes.crt;
ssl_certificate_key /etc/ssl/private/mes.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
}
4.3 接口防篡改与防重放
加密只能防偷看,但防不了坏人篡改数据。你想想看,如果中间人把生产指令里的"启动"改成"停止",那后果...所以我们需要额外的防护手段。
4.3.1 防篡改:签名机制
签名机制的原理很简单:把请求参数按规则排序,加上一个密钥,算出一个哈希值。服务端收到请求后,用同样的方式再算一遍,比对一下就知道数据有没有被改过。
我曾经在项目里用过HMAC-SHA256,效果不错。具体做法是这样的:
// 客户端生成签名
String message = "POST:/api/order:timestamp=1700000000&body=...";
String signature = HmacSHA256(message, secretKey);
// 请求头里带上签名
X-Signature: 2a3b4c5d...
X-Timestamp: 1700000000
4.3.2 防重放:时间戳+Nonce
防篡改搞定了,但还有个问题:攻击者可以把你的请求原封不动地再发一次。这就是重放攻击。怎么防?两个东西配合着用:时间戳和Nonce(一次性随机数)。
时间戳用来判断请求是否过期。我一般设5分钟的窗口,超过这个时间的请求直接拒绝。Nonce用来防止同一个请求被重复执行,服务端收到后把Nonce存起来,下次再遇到同样的Nonce就拒绝。
- 检查时间戳是否在有效窗口内
- 检查Nonce是否已经被使用过
- 验证签名是否正确
// 服务端验证伪代码
if (abs(now - timestamp) > 300) {
return "请求已过期";
}
if (redis.exists(nonce)) {
return "重复请求";
}
if (!verifySignature(params, signature, secret)) {
return "签名验证失败";
}
// 通过后,记录Nonce
redis.setex(nonce, 600, "used");
4.4 知识体系总览
说了这么多,我画张图帮你理一理思路。接口安全设计其实就三个维度:谁在调用(认证)、数据是否安全(加密)、数据是否完整(防篡改防重放)。
嗯,这张图基本把今天的内容串起来了。你想想看,认证、加密、防篡改防重放,这三个环节少一个都不行。我在实际项目中见过只做了认证没做加密的,也见过加密做得很好但没防重放的,最后都出了或大或小的问题。
好了,接口安全设计这块就聊到这儿。记住一句话:安全不是功能,是习惯。养成好习惯,你的MES系统才能跑得稳、跑得久。
公众号:蓝海资料掘金营,微信deep3321