普通视图

发现新文章,点击刷新页面。
昨天以前yearliny

服务端响应 RST, ACK ,可能是中间安全设备导致的

作者 yearliny
2024年10月11日 18:38

最近在一个项目中遇到了一个奇怪的问题,项目部署到客户提供的服务器环境中后,从互联网侧访问时好时坏,但是在服务器上访问是正常的,按照常理判断是防火墙的问题,但是客户联系的网络工程师一直没有解决该问题,其华为原厂工程师反馈说是“外网客户端访问时与服务器协商加密协议,服务器没有协商过程直接拒绝了,请再检查一下服务器的配置”,而又把问题抛了回来。

我虽笃定是是客户服务器环境的网络设备导致的,但没有证据也不能服人,所以用 Wireshark 抓包实际测试,这里记录排查过程。

这段抓包记录是一个典型的TLS握手失败的过程,在尝试建立安全连接时出现了问题。在 4835 & 4836 客户端发送了一个 Client Hello 包,这是 TLS 握手的第一步,结果在 4840 服务器突然发送了一个 RST, ACK 包,重置了连接。

由于之前测试过在服务器上是可以正常访问的,所以这这个时候我们需要考虑一个问题:这个 RST, ACK 包真的是服务器回复的吗?

从 RST 报文的 seq 来看确实可以和前序报文对应得上(由于SYN标志位在逻辑上占用1字节序号,所以 RST 报文的序号是第二个报文的序号加1)。

一个很好的判断一条流是否是同一个服务器发送的方法是对比同一个方向的报文的IP头中的 TTL(Time to Live) 值。由于 TCP 对乱序非常敏感,而网络设备逐包转发数据会引入更严重的乱序,因此网络中的设备一般都是逐流转发(按五元组,源目IP、源目端口、协议),所以,大部分情况下,在捕获的数据流中,同一条流的同一个方向的报文总是有相同的 TTL 值。

这里排查上面的抓包记录来看,从客户端到远程服务器的 TTL 值都是 128,服务端返回到客户端的包 TTL 值都为 119。而该 RST, ACK 包的 TTL 为 56,因此断定该包并不是真实服务器返回的,而是中间的网络设备伪造的。

将该问题返回给客户后,客户排查网络链路上的安全设备,在 IPS 中找到对应的日志,IPS 冒充服务器向终端发送 RST 报文拆链:

Oracle Linux 配置 CentOS 软件仓库镜像源

作者 yearliny
2023年8月28日 21:30

Oracle Linux 是基于 RHEL 的另一个“重构发行版”,和 CentOS 同属一类系统。国内使用该系统最大的一个问题就是没有对应的 Oracle Linux 软件仓库镜像源,并且网上也没有相关的资料,但考虑到是同属 RHEL 系统,并且官方如此的强调和 CentOS 兼容性,就想到尝试使用国内的 CentOS 镜像源仓库替代。

我这里使用 Oracle Linux 7 版本,对应 CentOS 7 版本,其他的大家各自对照略有出入。

# 1. 下载并导入 GPG 公钥
wget -O /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 https://mirrors.aliyun.com/centos/7/os/x86_64/RPM-GPG-KEY-CentOS-7
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

# 2. 配置仓库镜像源
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

# 3. 替换仓库源文件中的环境变量为具体的值
sed -i 's/\$releasever/7/g' /etc/yum.repos.d/CentOS-Base.repo

# 4. 生成缓存
yum makecache

简单说一下第四步操作:因为和 CentOS 系统的部分环境变量不同,所以按照该文件中的用法会导致找不到资源404错误。$releasever 环境变量在 Oracle Linux 下值为 7Server,而在 CentOS 7 系统中为 7,所以直接使用会出错。

EPEL 镜像源配置

# 下载镜像源
wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo

yum install epel-release

OK!现在已经可以正常使用 yum 命令了~

欢迎来到荷兰

作者 yearliny
2023年4月7日 20:39

有一篇 Emily Perl Kingsley 写的小短文《欢迎来到荷兰》,让我感受很深刻。要更多的去体验生活,而不是紧紧盯住一个目标,如果这样子生活就会缺少了乐趣。

经常会听到身边的很多人说:“等我怎么怎么样,我就会(可以)怎么怎么样了”,这样的句式可以演变成各种各样的例子:

  • 等我之后有时间和有钱了,我就报班学跳舞。
  • 等我财务自由了,我就去旅游。
  • 等等等等。。。

尤其在做一些对自己有益但又难以坚持的事情时,人会更多的这么想。但我想说的是:

  • 如果想要跳舞,完全可以在手机上找个舞蹈视频,在下班休息的时间练习个10分钟。
  • 如果想要跑步,大可不纠结早上还是晚上,变速跑还是匀速跑,先去顺着感觉跑上一段路。
  • 如果想要给所爱之人幸福的生活,大可不必总是在追求更丰富的物质生活,简简单单生活就有很多美好时刻。

你生活中时刻担忧的事情,可能就和一个针眼一样大,但是当你用放大镜对着看,针眼里的世界好像就是自己的全世界。如果试着放下放大镜,不去看针眼,去看看外面的世界。

就会发现自己每天经过的路边上有一朵很好看的小花,小草也是绿油油的,天空很蓝很干净,鸟儿在树上叽叽喳喳叫个不停。你爱的人和爱你的人就在你身边,你们身体健康、关系和睦。

这个时候就更会感受到生活之美,好像有一种神奇的力量在心中流动,也会更加积极的看待明天。不是说要有房子,有很多存款,能买各种各样的东西,去各个地方旅游才是有乐趣的,乐趣就在身边。

微信小程序防爬虫、黄牛方案设计

作者 yearliny
2022年6月20日 13:14

近期公司新上了疫苗预约功能,由于目前九价、四价疫苗的火爆程度,很快就吸引了各路牛马扫描爆破接口。因为缺乏防控措施,导致了这些爬虫、脚本对疫苗资源的抢占挤压,更有些不讲武德完全不做频率限制的爬虫脚本,一秒中查询调用11次,给服务产生了不良影响。

因此,需要设计一套方案来避免黄牛抢占资源,为广大群众创造出更加公平可靠的疫苗预约平台🎉

方案设计

一、请求响应加密

对报文使用加密可以避免被抓包,让攻击者抓包窃取到密文也无法理解。虽然目前小程序都是使用的 HTTPS 协议,但是攻击者依旧可以通过证书劫持的方法进行抓包,因此即使应用层已加密,报文本身是明文的依旧会有风险。

在使用加密时,存在一个问题就是密钥交换。在密钥交换的时候无法确保密钥被安全、无误的传输。如果密钥写到前端代码中,攻击者获取到前端代码后可以轻松窃取到密钥。在浏览微信小程序文档的时候,发现了微信小程序有一个获取加密密钥的API:UserCryptoManager.getLatestUserKey

const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
  success: res => {
    const {encryptKey, iv, version, expireTime} = res
    console.log(encryptKey, iv, version, expireTime)
  }
})

对报文请求进行加密,并在接口参数中加上时间戳参数,可以有效的避免被抓包和重放攻击,并且这个过程对于正常用户而言是无感的,完全不会影响使用体验。这个方案的缺点是,无法避免自动化UI脚本在真实的小程序运行环境下模拟操作,使用自动化UI脚本刷号源

二、请求频率限制

正常用户使用程序,会存在一定的行为特征,和机器的一个典型区别就是请求频率。在应用此方案的过程中,需要先统计出用户的使用频率,取一个阈值作为机器人的判断标准,当超出阈值后直接返回错误,一定时间后恢复。

为了最大程度的避免对正常用户的影响,在统计用户使用频率和阈值选取这块需要多加注意,并且可以结合多种频率限制规则,如一秒中允许请求多少3次,一分钟允许请求100次,一小时允许请求3000次。具体的频率限制规则需要按照具体业务来制定,具体的实现可以使用 Nginx 的 ngx_http_limit_req_module 轻松完成。

三、来源限制

目前注意到,脚本刷号的主要来源是PC端,即使用 Windows 端微信打开小程序,结合 Windows 上丰富的自动化UI工具刷号源。对于这种情况可以在代码中直接封死PC端,只允许在移动端操作,这块的选择需要自己权衡影响。

四、验证码

是的,这种最传统的、最影响用户使用体验的方案还是来了,为了区分正常用户和自动化UI脚本,需要使用验证码来区分开这类用户,验证码无疑是针对这个场景最有效的方案了。

当然,不一定非要使用最传统的字母数字验证码,甚至可以使用人脸识别,结合请求频率等规则使用。当用户请求频率到一定程度,需要人脸识别来判断是本人操作。

验证码的具体实现有很多种,这里不展开阐述。

五、机器学习风控系统(猜想原型)

这一步目前还在猜想阶段,因为最近在学习机器学习,意识到这是具有一定可行性的。黄牛党的刷号、预约、取消号源具有特定的行为模式,我们可以通过数据分析出特征,使用机器学习的方式识别出异常行为。

但是机器学习得出结果过程是一个黑盒,当出现用户投诉情况的话,不好核实处理。且存在成本相对较高的问题,所以此方案搁置。

知识“二道贩子”的作用

作者 yearliny
2022年5月5日 13:58

最近很少发表文章了,主要原因是觉得没有主创性强的点子,自己说的话只是现有内容的重复,不过是在互联网这个大垃圾桶里又制造些垃圾罢了。近日来,又忽然想到这样的“重复”不见得就是坏事。

古代素有重农抑商政策,政策产生的一个主要因素就是认为商业活动没有任何产出。只有农业才会生产粮食,手工业才会生产工艺品,而商业只是把这些商品转移过了一遍手,如同社会“蛀虫”。

而现代经济学早已证明商人的价值和意义。例如你平常肯定会在家附近的商店购买商品,而不会去工厂购买,那是因为你觉得商店离得近东西齐全,工厂虽然便宜但是离得远也不能一次购齐所有货物。这个过程中商店的意义就在于商品聚合,那一个人学习了某个知识,他把他所学的知识按照自己的理解又重新描述了一遍,这样的内容是否是有意义的呢?

有。在常见的心理学偏见中,有一条就是知识的诅咒。知识的诅咒说的是一个人对他已经掌握的内容,会潜意识的以为大家都知道,所以他在交流的时候,会忽略大量的他以为别人已经熟知的内容,导致了知识传播的障碍。而一个初学者,他复述学习的体会和理解,这往往对于另一个初学者很有帮助,尤其当他们具有相同的知识结构和知识深度的时候。

这就是为什么会有科普,并且科普是如此重要。在专业化如此之细的今天,我们掌握所有知识早已是不可能的,但是人类天生是有探索好奇之心的,不同的人有不同的探索程度。比如对一个大象的研究,有些人是想看看大象的样子,看到它是这么一个庞然大物便以满足;而有些人则还想了解大象的生活习性,大象是如何生活的;有些人想要了解大象的饮食规则;有些人想要了解大象消化系统的特点等等等等。不是所有人都是专家,每个人现有的知识结构差异也很大,所以在学习时面临的问题往往也要很大的差异。

想到此,我便觉得平日里可以多发表些文章看法,即便只是对生活的一个小感悟,对学习过程中的一个小总结,都总归是有用的。

Java 的 hashCode 与 equals

作者 yearliny
2022年4月28日 11:42

Java 的 hashCode 和 equals 是 java.lang.Object 的两个方法,这意味着所有的 Java 对象都存在这两个方法。当我们在使用 Map、Set 数据结构时,都要或多或少的和此方法打交道。亦或使用 Hibernate 在定义 Entity 实体类时,也需要注意这两个方法的重写。掌握 hashCode 与 equals 方法有利于加深对 Java 数据结构的理解,并且还能帮助我们避免一些低级 Bug。

Kotlin 与 Java 类似,但 Kotlin 的一些语法糖使得背后的类转换变得隐晦起来。例如 Kotlin 的比较操作符 == 实际调用的是类的 equals;Kotlin 可以针对列表进行取差操作,而这个操作的背后需要先把对应数据集合类型转成 HashSet ,然后使用 HashSet 的取差方法。

hashCode

hashCode 方法是由 Java 的哈希算法生成的 int 类型哈希值,既然是哈希值,这就意味着两个不同的对象也可能拥有相同的哈希值

哈希算法是把任意长度的输入转换成定长输出。

在 JavaDoc 中有说明此方法主要用于需要哈希表结构的数据结构,如 java.util.HashMapjava.util.HashSet ,hashCode 方法受限于以下三个法则:

  • 在程序运行过程中,hashCode 结果是不变的。
  • 如果两个对象 equals 相等,则 hashCode 方法必须相等。
  • 不要求两个 hashCode 相等的对象,equals 也相等。

这三个法则浓缩成一句话:

在程序运行阶段时,两个 equals 相等的对象,hashCode 结果值必须相等。

为什么这么要求呢?因为在使用哈希结构查询数据时,如使用 containsgetremove 等操作时,都会先使用哈希值匹配对应的 bucket,当多个对象出现哈希冲突时,在一个 bucket 中会存在以链表方式连结的对象列表,然后逐个使用 equals 方法进行匹配,以提高查询效率。

任何对象都有 hashCode 方法,如果没有手动重写,Object 的原生实现则会在某种程度上使用内存地址。

不同的 JVM,对 hashCode 的具体实现是不一样的。

equals

equals 方法相对而言就单纯了一些,这个方法就是用来比较两个对象的逻辑相等。类是编程思想中用于对现实世界建模抽象的工具,对应现实生活中的一类事物,而对象则是对应现实生活中的一个实体。现实生活中的实体都是可区分的,具有可标识性;在面向对象编程中使用对象映射现实生活中的实体,要保证对象的标识性,则是使用 equals 方法进行比对。

所以当我们要重写 equals 方法时,需要遵循的原则就是要让对象具有可区分性,能够和现实实体相对应。

开发中需要注意什么

平时开发过程中,大多数类都会使用内置的 hashCode 和 equals 方法,这对日常的开发过程没有任何影响,这常常会让我们忽略了它的重要性,这会在某些情况下造成难以察觉的Bug。

所以需要加深对此的理解,尤其是使用 ORM 或集合操作时,一定要注意 hashCode 和 equals 方法的重写。只要遵循上面提到的法则,就能够避免很多问题了。

Also See

Java中Date存储到MySQl字段时间不一致问题

作者 yearliny
2022年4月25日 12:29

问题情景

在 Java 代码中使用 new Date() 赋值日期,存储到数据库 DATETIME 字段后,在数据库中多了一秒,经过排查是数据库对Java Date 值进行了四舍五入,导致此问题。

问题剖析

Java 的 java.util.Date 类时间精确度到毫秒(milliseconds),MySQl 中的日期时间类 TIMEDATETIMETIMESTAMP 最大可以支持 6 位,即精确到毫秒(microseconds),以格式 type_name(fsp) 格式进行定义,如 DATETIME(3) 为定义精确到秒后 3 位(毫秒)。当不指定 fsp 的时候,默认值为 0,即最大精确度保留到秒。

此问题场景下,MySQL 的 DATETIME 未指定精确度,最大精确度为秒,而 java.util.Date 精确度为毫秒,MySQl会对末尾的时间进行四舍五入,当毫秒值大于 500 时,便会进 1 位增加一秒,造成了此问题。

从 MySQl 8 开始,可以通过启用 TIME_TRUNCATE_FRACTIONAL 参数使用截断模式,即直接移除末尾小数,不进行四舍五入。

测试代码

DROP TABLE IF EXISTS fractest;  
CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) ); 

INSERT INTO fractest VALUES  
    ('17:51:04.777', '2018-09-08 17:51:04.777', '2018-09-08 17:51:04.777');  
INSERT INTO fractest VALUES  
    ('17:51:04.555', '2018-09-08 17:51:04.555', '2018-09-08 17:51:04.555');  
INSERT INTO fractest VALUES  
    ('17:51:04.444', '2018-09-08 17:51:04.444', '2018-09-08 17:51:04.444');  
SELECT * FROM fractest;

Also see

不要低估了Beta的力量

作者 yearliny
2022年2月3日 19:37

在投资市场中,学院派投资者有一种区分个人能力和市场行情的理论概念称之为Alpha和Beta:一个投资者的择股能力为Alpha,而对应股票所在行业收益为Beta。因此在评价这个投资人的时候要区分他投资所在行业的收益和他相对于行业的超额收益,用于衡量其本人的真实水平。

后来我发现这个概念可以应用到其他地方,帮助理解和把握问题。比如在在北京有两个人,一个是程序员和一个农民工,其中程序员的月收入是一万五,农民工的月收入为一万,单从月收入上来看可以认为程序员比这个农民工“厉害”。但我们接着加上行业平均收入这个条件,北京程序员平均收入两万,而北京农民工平均月入六千;加上了Beta作为比较基准后我们可以看到,这个农民工的个人能力是“优于”程序员的,这个农民工获得了超出周边人的超额收益。

这给人很大的启发,就是一定要注重大趋势的力量,大趋势给人的助力往往会超出个人的努力所起到的作用。还是用这个举例,就是这个农民工努力的工作(获得了超出均值的回报),也不如一个不努力的程序员所得到的收入。理解了这个概念,就能对雷军的“站在风口上猪都会飞”这句话有更深的理解了。

《飞猪理论》

当然Beta和Alpha是个比较抽象的概念,应用到不同的领域中需要结合对应领域的因素。比如在工作、公司经营这块,重要的Beta因子有地域(如县、市)、行业这两个因素。

Beta给人的启示是要关注大环境的力量,这种不以个人意志为转移的力量可以影响到大量处于这个环境的群体。比如当你处于经济飞速发展的城市,你的收入向上边际改善的可能就更大,当你处于景气度很高的行业,你向上边际改善的空间也就越大。反之亦然,当你处于没落的城市和行业,你向下边际恶化的可能就越大。

Beta决定了你的基准和天花板,Alpha决定了你在这个环境中所处的相对水平。作为个人来说,不仅要提升自己的职业技能,也需要紧盯环境变化,从而可以处于进可攻退可守的地步

现实生活中人们往往会更注重于个人的努力,而忽略了环境的选择,这对于做出思考和判断来说是极其不利的。对于已经享受到Beta红利的人而言,也要认识到这个是社会的红利,不要骄傲自满,更不要把时代的Beta当作自己的Alpha。

“劣币驱逐良币”在婚恋市场中的表现

作者 yearliny
2022年1月11日 20:34

也许会有很多人感觉好男人(好女人)很少,渣男(渣女)却很多,这某种程度上可以用劣币驱逐良币来解释。我们可以假设好男人、一般男人、坏男人的占比呈正态分布,即中间高两边低的曲线。

🎗此规律对于女性也是通用的,为便于举例说明下面均为男性,不再对此额外说明。

男性质量正态分布曲线

如图所示,X轴为好坏的程度,X越小则越坏,X越大则越好,Y轴为数量,值越大则代表数量越多。可以看到好男人和坏男人约等量的少,而一般男人的数量最多。但是就生活经验来说,好男人在婚恋过程中分手可能性小,而女性一般找到了好男人也不会让其离开,所以好男人可能谈一两个就不会再谈了;与此相反的是,坏男人会和更多的女性交往。

这里就引出一个概念就是换手率,换手率=交往对象数量÷适龄对象数量。在适龄对象数量一定的情况下,交往的对象数量越多则换手率越高,换手率高则意味着有更高比例的人交往过。

因此,坏男人流通性高,好男人流通性低,导致了市场上流通的更多的是坏男人,人们的感觉就是渣男比好男人多。

这就是劣币驱逐良币——好男人都被藏起来了,坏男人一直在市面上流通。

❌
❌