做设备集成这些年我越来越觉得PLC这个家伙被低估了。大家默认它就是干逻辑控制的线圈、电机、气缸、传感器梯形图一拉完事。直到有一次某设备厂找我处理一台设备的“乱改参数”问题——设备交付到客户手里后操作员对工艺参数随意改动生产出来的产品批量报废售后电话直接被打爆。客户需求很朴素能不能让设备只认特定的人能不能每次开机的验证口令都不一样这就是我开始研究信捷PLC随机密码和动态验证码功能的起点。其实把信捷PLC当成一台“带工业接口的微型计算机”来看很多看似不PLC的应用都能落地随机密码、动态验证码、随机延时、设备授权……这篇文章我把自己在这条路上验证过的方案、踩过的坑以及几条能直接抄作业的梯形图和结构化文本逻辑写出来。适合工控工程师、设备厂技术人员以及刚接触PLC、想拓宽思路的读者。你不需要一开始就精通ST语言跟着思路走你也能在自己的设备上实现这些功能。1. 随机密码和动态验证码到底解决什么实际问题讲随机密码之前先要搞清楚PLC本身是一个“谁都能碰”的设备。最常见的尴尬场景是——触摸屏上设置参数权限出厂设了一个固定密码密码在工人之间传来传去等于没有。尤其是设备发往外地之后远程改参数、锁定参数、限制操作时间这些需求用固定密码根本管不住。我把这些年遇到的需求归了个类这几个场景基本覆盖了所有找上门的客户。第一类是设备参数锁定。设备卖给客户后工艺参数、温度上限、压力下限这些关键设定值不允许现场工人随便动。厂里要改参数必须由设备厂家远程给出一个当次有效的动态密码才能进入高级菜单。以前用固定密码发出去几次就在车间里传开了改成动态验证码之后哪怕操作员把上次的验证码抄在纸上下次也进不去。第二类是班次与人员管控。同一个车间三班倒不同班次用不同的随机验证码启动设备实现“谁当班、谁启动、谁负责”。验证码可以一天一换也可以细化到4小时一换。真出了问题能直接追溯到具体班次和操作时间窗口这对质量事故分析帮助巨大。第三类是设备租赁和分期付款场景。设备以租代售或分期付款到期未续费需要锁机。以前是到日期直接锁死但客户总有话说——“我根本没到日期”“你们时钟不准”。实际上就是PLC实时时钟被改过或者断电保持区被清掉了。用动态验证码做解锁后逻辑变成设备锁机屏幕显示一串随机码客户需要把码发给厂家厂家通过算法算出解锁码输入后恢复使用。这个功能帮某设备厂把逾期回款率提了一倍多——因为“绕过去”的成本变高了客户只能老实找厂家。第四类是最常见的防误操作的二次确认。设备上某个关键按钮比如吹气清枪、高温排料、模具锁紧一旦误触可能造成整批产品报废。我做过一台设备启动该动作前触摸屏会显示一个6位随机数字操作员必须准确输入才执行。这个比“弹窗确认”可靠得多——弹窗点“确定”是肌肉记忆而看一串随机数再输入必须动脑子。这四个场景有个共同点它们都不是密码学意义上的安全需求而是“提高操作门槛、增加追溯性、防止无脑操作”的工业管理需求。想清楚这一点特别重要。因为PLC能提供的随机性远达不到银行级安全标准更不是用来对抗专业攻击者的。但如果把目标定位成防误操作、防随手破解、防密码传阅它的性价比就非常高了。1.1 关于安全边界的实话先泼一盆冷水。信捷PLC的随机密码和动态验证码能做到的是“提高非授权操作的难度”而不是“绝对安全”。任何懂PLC的人如果物理接触到设备都能通过编程口读取程序甚至强制输出——这不是应用层密码能防住的。所以这个方案的正确用法是防普通操作员、防随手乱试、防密码传阅而不是防工程师级别的恶意篡改。明确这个边界很重要否则你会在错误的方向上浪费大量时间。比如有人想在PLC里实现完整的AES加密且不说算力够不够单是密钥管理就够头疼的。认清“防谁”之后所有设计决策都变得清晰了。2. PLC的“随机数”从哪来没有硬件随机源的办法这是整个方案的技术核心。计算机做随机数要么靠硬件噪声要么靠复杂的算法库。信捷PLC这种小型PLC指令集相对简单、运算资源有限没有硬件随机数发生器也没有加密库。那随机数到底从哪来我试过不少路子最终稳定下来的是一个组合方案把几个“看起来一直在变”的量混合起来做扰动。第一个来源是系统实时时钟。PLC内部时钟的毫秒值一直在走哪怕是同一秒内毫秒位的低字节也一直在跳变。第二个来源是扫描周期计数。PLC主程序每扫描一次内部一个计数寄存器就加1这个值在几十毫秒的尺度上不断变化。第三个来源是运行状态量。比如某台设备的累计运行时间寄存器或者模拟量通道的噪声低位——只要环境里存在微小的电信号波动这个值就在变。把这三个量做异或运算得到一个种子值再对种子做多次循环移位和再次异或。循环移位的作用是把种子里的位信息“搅匀”原本只变化低几位循环移位之后高几位也会跟着变化。这样就能得到一个分布比较均匀的伪随机数。用结构化文本写出来大概是这样的逻辑// 伪随机种子生成 RAND_SEED : (TIME_MS AND 16#FF); // 取时钟毫秒低字节 RAND_SEED : RAND_SEED XOR SCAN_CNT_LOW; // 混入扫描计数低字节 RAND_SEED : RAND_SEED XOR (AI_CH_LOW AND 16#0F); // 混入模拟量低4位 // 循环移位打散 FOR I : 0 TO 7 DO IF (RAND_SEED AND 16#01) 0 THEN RAND_SEED : (RAND_SEED SHR 1) OR 16#80; ELSE RAND_SEED : RAND_SEED SHR 1; END_IF; // 再混入当前秒的低位 IF (SEC_LOW AND 16#01) 0 THEN RAND_SEED : RAND_SEED XOR 16#A5; END_IF; END_FOR;这段逻辑的核心思路用大白话说就是把几个“不稳定”的低位数据取出来互相搅一搅再循环挪位让输出的每一位都跟输入的多位相关。这样即使外层环境比较稳定只要设备在运行扫描周期和时钟就一直在变种子就一直在变输出的随机数就不会出现长时间重复。有人可能会问为什么直接用时间戳就行还要做循环移位因为在PLC里直接读时间戳连续读几次拿到的可能是同一个值——扫描周期是毫秒级而你生成密码的时间点可能间隔几分钟。直接取秒数做因子会得到大量重复值。加了扰动和移位之后哪怕种子只有几十毫秒的差别输出也会有明显差异。我实测过连续采集500次随机数肉眼观察没有出现可感知的规律性重复。对于工业应用这个程度已经足够了。当然我也试过另一个备选方案直接用信捷某些系列自带的随机数指令。但那个随机种子来源不透明不同批次固件表现不一致。从可解释性出发我最终选了自建扰动混合方案——出了问题能查、能改、能解释这一点在现场维护时极其重要。2.1 随机种子与扫描周期的“竞速陷阱”这里有个大坑第一次做的人基本都会踩。当你从主程序连续取随机种子时由于整个程序扫描一圈只要十几毫秒你可能会在一个扫描周期内得到好几个不同的随机数——因为它们混入了扫描计数。如果你的密码生成逻辑里用了两次“读随机数”前后读到的值不一致会导致生成的密码和校验时用的预期密码对不上。解决办法随机数只能“采样一次、锁存使用”。我习惯的做法是先用一个脉冲沿触发采样把随机数存到一个独立的锁存寄存器里后续所有逻辑都引用这个锁存值绝不在同一段逻辑里第二次调用随机数生成。这个教训是实打实买来的——第一批做验证码功能时现场连续报“验证码输进去说错误”排查了一整天最后发现就是主程序里无意中触发了两次随机数生成一次用于显示一次用于校验。同样的道理也适用于HMI读取。如果你在触摸屏上直接引用随机数生成寄存器的地址做显示屏幕刷新一次就读一次肉眼会看到数字疯狂跳动。正确做法是生成后放到专用的显示寄存器并且只在生成完成的瞬间更新一次。3. 随机密码功能从随机数到能用的密码串有了随机数下一步就是把它变成人眼能看、手指能输的密码。这里要解决三个问题随机数的取值域、字符映射规则、校验逻辑。取值域方面我一般生成6位或8位纯数字密码。为什么不用字母因为现场操作员普遍年纪偏大触摸屏输入字母要切键盘极容易输错。6位纯数字是实测下来体验最好的方案——安全性足够100万种组合输入体验也最好。如果你是在HMI上通过USB键盘输入可以考虑8位数字字母混合但触摸屏输入还是老实做纯数字。字符映射的逻辑是这样随机数生成后拿到的是一个0到255的字节值。要做映射最直白的方法是取模。比如生成6位密码就把随机数对10取模得到0到9的一位数字然后循环6次取6位。但这里有个细节如果对同一个随机数连续取模得到的6位数字相关性太强前一位是3后一位大概率也在3附近。所以正确做法是每取一位之前先把随机数重新做一次循环移位或重新混入时间低位让每一位的输入源都不一样。实际使用的生成逻辑参考如下FOR J : 0 TO 5 DO // 每一位生成前先打乱一次 RAND_TMP : (RAND_LOCKED SHL 1) XOR (RAND_LOCKED SHR 5) XOR J; // 取0到9 PASS_DIGIT[J] : RAND_TMP MOD 10; // 下一轮使用更新后的值 RAND_LOCKED : RAND_TMP; END_FOR;这样输出的6位数字每一位分布都相对独立粗略测试基本没出现过“666666”“888888”这类强规律串。虽然概率上讲这类串必然会出现但工程上可以加一道过滤生成的6位中如果某一位重复超过3次就重新生成一次。这个过滤提升的是观感不是安全性但能让设备显得更专业。密码生成之后第二个问题是PLC怎么校验如果设备单机运行、不联网那就必须PLC自己存一份预期密码然后比对输入值。PLC内存有限不可能像服务器那样存几十个历史口令。我一般只存最近3条当前有效密码、上一个密码、上上一个密码。这样即使操作员上一次输错后重新生成也能做容错比对。校验逻辑的另一个关键是“次数锁死”。我做的防护是同一轮密码连续输错5次锁定10分钟期间任何输入都无效。目的是防暴力穷举——6位纯数字组合是100万种如果允许无限次尝试理论上都能试出来但5次锁定10分钟100万次尝试就变得极不划算。这个机制很小但非常重要它决定了这个功能是“防误操作”还是“形同虚设”。校验通过之后的逻辑也要想清楚。我习惯给密码校验设计三个状态WAIT等待输入、VERIFIED已通过、EXPIRED已过期。VERIFIED状态下相关操作才允许执行一旦执行完成立即回到WAIT并要求重新生成新密码。实现上就是几个内部继电器和比较指令的事但如果不设计这个状态机很容易出现“输入一次密码永久有效”的尴尬情况——那跟固定密码就没区别了。3.1 断电保持的细节一个很容易忽略的点预期密码存放在什么寄存器区。信捷PLC的寄存器分普通区和断电保持区。如果把当前预期密码放在普通区设备断电重启后随机数重新初始化之前生成的密码就全废了——操作员手里拿着一个密码重启后怎么都输不对。但如果放在断电保持区又可能出现“密码还是旧的但随机数种子已经变了”的问题。我的处理方式是密码锁存值放断电保持区随机数种子重新初始化时不保留旧密码直接清除并生成一个新的。简单说断电重启后旧密码一律作废HMI上明确提示“设备重启请重新获取验证码”。这个逻辑在意外断电频繁的车间里特别重要——如果不做客户会认定你们的验证码功能是坏的。4. 动态验证码给权限验证加上“时间维度”如果说随机密码解决的是“每次都不一样”那动态验证码解决的就是“只在特定时间段内有效”。我这里的动态验证码基本借鉴了银行动态令牌的思路只是实现上做了向PLC技术栈的妥协。核心思想是验证码 f(时间因子, 秘密值)。这个函数在PLC里做不了复杂的哈希我用了多项式变换加异或配合取模输出6位数字。秘密值存在PLC的断电保持区里相当于钥匙现场操作员不知道。时间因子取PLC系统实时时钟的分钟加秒。两者做运算后输出6位数字。设备端同样用这个算法根据当前时间算出预期码如果操作员输入的码和预期码一致且密码还没过期就放行。听上去不复杂但落地时有三个工程挑战时间同步、时间窗口、防重放。时间同步方面PLC的实时时钟开机后会一直走但电池没电或长时间断电后可能归零。做法是在HMI上做一个校时入口由设备管理员定期校准或者每次开机时从触摸屏时钟同步。触屏本身的时钟也靠电池维持但电池更换方便比PLC内部电池稳定得多。时间窗口方面用户输入验证码到PLC校验收证码之间存在时间差哪怕手速再快也要几秒钟。如果算法以“分钟”为时间因子问题不大但如果以“秒”为因子就必须考虑窗口期。我设计的容错窗口是以当前分钟为准同时接受上一分钟生成的有效码。也就是说你在59分59秒生成的验证码到下一分钟的第1秒输入依然能通过前提是不超过设定的过期时间。实现上就是同时用当前时间因子和上一时间因子各算一遍预期码任一匹配即通过。防重放方面动态验证码如果不做单次性限制操作员完全可以把今天的验证码拍照保存明天接着用——时间因子变化后这个码明天自然无效。但如果时间因子只精确到分钟同一分钟内验证码可重复使用。所以我在验证通过后会把这次的时间因子记录到“最近使用时间”寄存器里下一次校验时如果时间因子相同直接拒绝。这相当于给验证码加了一次性属性。算法本身写出来很简短// 时间因子分钟 秒 TIME_FACTOR : MINUTE * 60 SECOND; // 秘密值混合 TMP : TIME_FACTOR XOR SECRET_KEY; // 多项式变换乘加混合 TMP : (TMP * 37 11) MOD 1000000; // 保留6位 VERIFY_CODE : TMP;这个算法不是密码学级的还差得远。它防的是“拿到上次验证码也没用”“不知道规律没法自己算”这种水平。如果真有人拿到PLC程序并且理解了算法那验证码就是透明的。但正如开头所说物理接触级别的威胁不在本方案的边界内。4.1 HMI输入数字键盘的实现提示动态验证码最终要在触摸屏上输入。信捷软件中屏幕画面做数字输入框很方便绑定一个寄存器就行。但我吃过一个亏数字输入框默认可能带小数点或者输入上限是16位导致6位验证码输入时尾数自动补零或录入异常。建议把输入框的数据格式设为整数、位数固定6位、无符号并开启“回车确认”事件——操作员输入完点击确定按钮时才把输入值写入PLC的校验寄存器。不要用实时联动模式否则输入过程中PLC可能已经开始校验输到一半就被判定错误了。另外HMI上的“获取验证码”按钮一定要做成带延时的按下后先执行随机码生成逻辑再把结果寄存器的值显示出来中间留出至少200毫秒的间隔。否则可能会看到屏幕显示的是上次的旧码。这个问题我在现场调试时出现过最后定位是HMI画面刷新速度和PLC扫描周期的竞争问题。5. 同一套随机数核心能复用到哪些场景随机密码、动态验证码只是这套随机数核心的第一层应用。一旦你打通了“PLC里能稳定产生伪随机数”这个基础能力能做的事就多了。下面这几个方向都是我在实际项目里用过的。第一个是随机错峰启动。车间里多台大功率设备同时上电瞬时电流冲击很大容易顶掉车间总闸。传统做法是人工错开开机时间但操作员经常忘。我的做法是每台设备开机时生成一个0到10秒的随机延时在各自触摸屏上一键启动后延时时间到再接通主接触器。因为是随机延时多台设备同时上电时大概率不会撞车。既不需要复杂的通信协调也不需要固定的错峰表实现成本极低。实测在4台22kW设备同时上电的场景下总进线电流明显平滑了。第二个是随机抽样检测。质检环节需要每100件抽检1件但如果严格按固定计数操作员慢慢就摸出规律专挑没抽中的批次走捷径。改成随机抽检后每台设备维护一个计数器每次计数加1满一定数量就生成一个随机数随机数落在设定阈值内才触发抽检。这样抽检时机不可预测质检的威慑力提升很多。这个需求是某食品包装线给我的灵感后来用在类似过程的管控上也很顺手。第三个是设备演示模式。给客户做设备演示时设备长时间运行同一个动作序列容易显得死板。我做过一个演示模式每次演示循环里动作顺序固定但各环节的停顿时间用随机数控制比如喷涂机的走位停留点在0.5秒到1.2秒之间随机。客户观感上会觉得设备动作更聪明、有变化感。这个应用虽然偏花哨但对设备销售演示很有用。第四个是“加盐”混淆。设备的关键参数校准值存在PLC的断电保持区如果担心有人通过触摸屏调试菜单看到并复制校准值可以在校准值存取时混入一个随机数做浅层混淆异或翻转。这样即使有人通过调试界面读到存储值也看不出真实校准参数。注意这只是加一道门槛不是加密但足够挡住绝大多数非恶意操作。这四个场景有一个共同特征都不需要额外硬件成本也不增加多少扫描负担只是把同一套随机数核心模块在不同功能块里复用。我在程序里把随机数生成做成了一个带使能端的子程序FB每次只需要触发使能端就能拿到一个当前锁存的随机数。这样复用起来非常干净不会出现逻辑冲突。5.1 随机数子程序的结构设计这个子程序我给十几个项目复用过了结构上相对稳定。输入只有一个EN使能触发输出有两个RAND_VAL16位随机数值、VALID本次有效脉冲。内部实现就是前面讲的扰动混合加循环移位。使用上要注意同一时刻只允许一个调用点触发它交叉触发会导致锁存值互相覆盖。如果程序里多处需要随机数我习惯用不同的子程序实例每个实例内部独立维护自己的锁存区。虽然多占几个寄存器但彻底避免了互相干扰。这个设计原则在程序复杂度上来之后尤为重要——共享随机数模块是最容易踩的雷。6. 这套方案踩过的坑和工程化建议这部分整理一下我在不同设备、不同现场踩过的典型问题按“现象—原因—处理”的方式写出来应该能帮后来者省不少时间。我直接做成表格方便查阅。现象根本原因处理方式验证码总是对不上随机数被多次触发显示值和校验值不一致锁存采样脉冲沿触发一次采样全局使用输入框输6位码PLC收到的却是补零后的数HMI输入框格式设置错误带小数点或位数不对设为整数、6位、无符号、回车确认模式断电重启后授权全部失效随机数重建后预期密码变化旧密码作废HMI提示重新获取验证码密码区断电保持验证码一直提示过期PLC时钟被重置或电池耗尽HMI定期校时或改用运行时间因子兜底生成的随机数分布不均匀梯形图实现循环移位易丢失高位信息改用ST语言编写随机数模块程序下载后PLC不知道当前有效密码断电保持区被程序下载复位初始化时用魔数校验密码区完整性被清则重新生成6.1 调试与验证的实用技巧最后分享一个调试方法。验证随机数功能是否可靠不能只看几十次我习惯做这三件事。一是连续触发1000次随机数生成用HMI的配方画面或SD卡记录结果肉眼检查有没有明显的周期重复。二是人为制造时钟跳变校时几分钟确认验证码在时间窗口边界的行为符合预期。三是模拟断电重启确认密码区和状态寄存器的处理逻辑正确。这三步全部通过之后我才敢把设备发往现场。另外程序里正式版本和测试版本建议用单独的调试触点切换测试代码直接留在正式程序里不仅占资源还有被误触发的风险。我见过有人把强制性的测试语句留在正式程序里到了现场设备一动起来就报奇怪的错误排查很久才发现是那行测试代码在作怪。6.2 关于工程边界的一点经验最后想强调一下反复提到的边界问题。我遇到过客户希望在PLC里实现“防篡改”的诉求但PLC程序本身可以被编程软件直接读取上传密码机制在拿到程序的人面前没有秘密。正确的工程边界是用随机密码和动态验证码来解决操作权限、流程追溯、防误操作问题如果需要防篡改应该在设备管理层面解决——比如锁编程口、加密程序文件、设置多级密码体系。这个项目整个过程走下来我最大的感受是PLC的应用边界往往不是由硬件决定的而是由工程师的思维方式决定的。一台信捷PLC的成本可能只相当于一台低配电脑但只要把它的运算能力用好它能承担的职责远超“线圈控制”。随机密码和动态验证码只是入门背后那套“把系统状态混合成随机性”的思路才是能在更多场景复用的核心资产。如果你也在自己的设备上遇到了固定密码传阅、操作员乱改参数、设备到期难追溯这类问题按这个思路去改造一台PLC应该不会让你失望。试通之后你会发现原来一台小小的PLC也能做出很有“科技感”的功能。欢迎在实际项目里跑出结果后回来交流你的落地过程。