分类 默认分类 下的文章

关于加解密想到的

能比改别人写的BUG更恶心的事情,大概只有调别人写的接口了吧

接口调用的时候,为了保障敏感数据安全,一般都会做加密或者签名。md5,sha1,sha256,hmac,各种签名算法,128,256,512,cbc,cfb,AES下茫茫多的加密方式,跨语言实现中各种实现方式,简直叫人焦头烂额。

帮别人踩坑

之前做数据加解密传输基本都在自己的项目中,不同组件虽然是不同语言实现的,但是实现细节自己比较清楚,没有遇到什么问题。最近第一次碰到加解密的坑是一个只会py的小胖子,他要去接别人的API,对方用php实现了一套签名算法 hash_hmac('sha256')。他用py的hashlib.sha256自己实现了一套hashHmac,哈希结果死活不对,网上搜也基本都是这样实现,我帮小胖找了好久,才发现要使用base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())

自己踩坑

上一次是接华为云市场的时候,对方在文档中只说了要用AES-CBC-128或者AES-CBC-256来进行加解密,但是我这边用php无论如何都解密不了。无奈之下,只好去看官网demo,结果java 的demo 还是一个代码片段,然我这种没环境,没IDE的人,连调试都做不到。实在没办法,只好人脑编译,然后我看到了这几行

KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");

secureRandom.setSeed(keyBytes);

keyGenerator.init(encryptType, secureRandom);

SecretKey key = keyGenerator.generateKey();

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));

我的天呦,原来是Key做了一次哈希再拿去运算的。。。

帮别人写代码

是的,就是帮别人写代码。

客户要对接自己的短信通知系统,需要我们把通知内容下发给他们。对接的小哥有点搞不定,一定要我们给他一个demo,c#的,我从来没写过,我们组也没人写过,我们公司也没人写过。

本着原理相同,工具不同的态度,我决定给小哥撸一个demo。不得不说,在陌生的领域里,举步维艰。算法,demo什么的网上找到了很多,但是一直没有可以运行的环境。vs下了一下午都没好,网页工具又非常不给力,调试到怀疑人生。下好vs后,网上的demo一直报错说CFB方式不支持,怀疑人生。晚上和同组小哥讨论的时候发现:只要在vs上创建 .net工程,不要创建.net core工程就不会报错。。。 微软爸爸你真棒! 弄好环境之后,二十分搞定。

一些牢骚

可能是我对其他语言了解不够深入,也有可能有些误解。但是,从易用性这点上来说,PHP真的是世界上最好的语言。我看到有好几个人用多种语言实现了AES的某一个算法来做对比,PHP版本的总是最简洁的。简洁不仅是指代码行数少,更是对使用者和阅读者心智的解放。

可以从使用加密或者签名的意图出发去想一下,我为什么要这么做?我只是想要保障数据安全!不要和我说经过多少轮的变换,能抵抗多么大规模的暴力破解。我只需要知道是用 CFB 还是 CBC 安全,我要用256还是512。只要告诉我AES-128-CBC,我只想用一个函数,一行去解决这个事情。我不想知道你的key是经过md5,还是sha256之类的鬼方式计算的。也不想知道iv是固定的还是放在密文前面还是后面,是都base64还是部分base64。我只想decrypt(method,cipher)

MySQL unique and Laravel soft delete

A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. For all engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL.

laravel 的 soft delete trait 使用 deleted_at 来作为约束。由于需要同时使用唯一和软删除两个特性,所以把 deleted_at 也作为 unique 的一个联合键。测试的时候发现,当 deleted_at 为 null 的时候,可以无限插入,unique并没有约束成功。MySQL官网描述如上,解决方案也容易,直接将 deleted_at 设置为 not null 即可

PHP 变量存储初探

前几天在排查一个系统BUG的时候发现一段很有意思的代码

$obj=Obj()::where()->get();//这里是eloquent方法,大概15K条数据
foreach($obj as $k=>$v){
        bar();
    if($v->user){//eloquent 的has one
        foo();
    }
}

这段代码撑爆了单线程128M的内存限制。原因就在循环中$v->user没有释放内存。根据PHP手册对foreach的描述,我们可以得知这里的$v是拷贝赋值,并不是引用赋值。那么为什么每次循环结束的时候,这些内存没有被回收?

答案在于php存储变量的方式中。PHP中的变量存在一个叫zval的结构体中,我们所用的$a,$b...都只是一个变量的标签,变量真正的值都存在zval容器中。其实每次循环结束$v所占用的内存都已经被回收,但是销毁的 $v只是一个符号,对象真正使用的空间并没有被回收。看完下面这段代码,就应该能很容易的了解到底发生了什么。

echo "<br/>----------- Init a -------------<br/>";
$a=new stdClass();
$a->foo=1;
xdebug_debug_zval('a');

echo "<br/>----------- Init b ------------<br/>";
$b=$a;
$b->foo="bar";
xdebug_debug_zval('a');
xdebug_debug_zval('b');

echo "<br/>----------- Unset b ------------<br/>";
unset($b);
xdebug_debug_zval('a');

这段代码将返回:

----------- Init a -------------
a:
(refcount=1, is_ref=0),
object(stdClass)[1]
  public 'foo' => (refcount=1, is_ref=0),int 1

----------- Init b ------------
a:
(refcount=2, is_ref=0),
object(stdClass)[1]
  public 'foo' => (refcount=1, is_ref=0),string 'bar' (length=3)
b:
(refcount=2, is_ref=0),
object(stdClass)[1]
  public 'foo' => (refcount=1, is_ref=0),string 'bar' (length=3)

----------- Unset b ------------
a:
(refcount=1, is_ref=0),
object(stdClass)[1]
  public 'foo' => (refcount=1, is_ref=0),string 'bar' (length=3)

这里销毁了$b,但是却并没有将对象销毁掉。所以,在上面的的foreach中,orm对象不停的叠加user中的属性,而一直没有被回收,最终撑爆了内存。

解决方案是我司zkq指点我的,他让我尝试下深拷贝,完美解决。

$obj=Obj()::where()->get();
foreach($obj as $k=>$v){
        $value = clone $v;//克隆一个对象
        bar();
    if($value->user){//使用克隆的对象,循环结束立刻销毁
        foo();
    }
}

参考: