UioSun

UioSun 查看完整档案

上海编辑江西应用科技学院  |  迷之学科 编辑喵斯拉  |  PHP 工程师 编辑 blog.uiosun.com 编辑
编辑

use google find the world. "该用户太懒", dead was yesterday.

个人动态

UioSun 提出了问题 · 2月23日

实例化一个长类 vs 数个短类,谁效率低?

主要场景是 PHP or C#

如果要将多控制器都用到的方法抽离出去,引发一个疑问:

包装数十个方法的 Logic vs 包含一个方法的 Tasks。哪种分层更合适?

背后的考量是:

  • 实例化一个或几个对象——每个包含一组功能,但本次请求中,80% 都不会用到。
  • 实例化数个或更多对象——每个包含单个功能,但本次请求中,实例了多个类。

哪种性能更好?


Autoload 现在都是 lazy load,是不是意味着一个冗长的类,只会实例化它本身的代码,而不会继续加载其中代码中的 new 等关联行为?

对语言内部机制了解不够深刻,我去测一下实例化 50000 个很短的类和实例化 50 个贼长的类,哪个更快些。

关注 3 回答 0

UioSun 赞了文章 · 2020-07-24

前后端分离架构下CSRF防御机制

原文: http://feclub.cn/post/content...

背景

1、什么是CSRF攻击?

这里不再介绍CSRF,已经了解CSRF原理的同学可以直接跳到:“3、前后端分离下有何不同?”。

不太了解的同学可以看这两篇对CSRF介绍比较详细的参考文章:

如果来不及了解CSRF的原理,可以这么理解:有一个人发给你一个搞(mei)笑(nv)图片链接,你打开这个链接之后,便立刻收到了短信:你的银行里的钱已经转移到这个人的帐户了

2、有哪些防御方案?

上面这个例子当然有点危言耸听,当然可以确定的是确实会有这样的漏洞:你打开了一个未知域名的链接,然后你就自动发了条广告帖子、你的Gmail的邮件内容就泄露了、你的百度登录状态就没了……

防御方案在上面的两篇文章里也有提到,总结下,无外乎三种:

  1. 用户操作限制,比如验证码;

  2. 请求来源限制,比如限制HTTP Referer才能完成操作;

  3. token验证机制,比如请求数据字段中添加一个token,响应请求时校验其有效性;

第一种方案明显严重影响了用户体验,而且还有额外的开发成本;第二种方案成本最低,但是并不能保证100%安全,而且很有可能会埋坑;第三种方案,可取!

token验证的CSRF防御机制是公认最合适的方案,也是本文讨论的重点。

3、前后端分离下有何不同?

《CSRF 攻击的应对之道》这篇文章里有提到:

要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的

我们前端架构早已经告别了服务端语言(PHP/JAVA等)绑定路由、携带数据渲染模板引擎的方式(毕竟是2011年的文章了,我们笑而不语)。

当然, 前端不要高兴的太早:前后端分离之后,Nodejs不具备完善的服务端SESSION、数据库等功能。

总结一下,在“更先进”的前端架构下,与以往的架构会有一些区别:

  • Nodejs层不处理SESSION,无法直接实现会话状态数据保存;

  • 所有的数据通过Ajax异步获取,可以灵活实现token方案;

实现思路

如上文提到,这里仅仅讨论在“更先进”的前端后端架构背景下的token防御方案的实现。

1、可行性方案

token防御的整体思路是:

  • 第一步:后端随机产生一个token,把这个token保存在SESSION状态中;同时,后端把这个token交给前端页面;

  • 第二步:下次前端需要发起请求(比如发帖)的时候把这个token加入到请求数据或者头信息中,一起传给后端;

  • 第三步:后端校验前端请求带过来的token和SESSION里的token是否一致;

上文提到过,前后端分离状态下,Nodejs是不具备SESSION功能的。那这种token防御机制是不是就无法实现了呢?

肯定不是。我们可以借助cookie把这个流程升级下:

  • 第一步:后端随机产生一个token,基于这个token通过SHA-56等散列算法生成一个密文;

  • 第二步:后端将这个token和生成的密文都设置为cookie,返回给前端;

  • 第三步:前端需要发起请求的时候,从cookie中获取token,把这个token加入到请求数据或者头信息中,一起传给后端;

  • 第四步:后端校验cookie中的密文,以及前端请求带过来的token,进行正向散列验证;

当然这样实现也有需要注意的:

  • 散列算法都是需要计算的,这里会有性能风险;

  • token参数必须由前端处理之后交给后端,而不能直接通过cookie;

  • cookie更臃肿,会不可避免地让头信息更重;

现在方案确定了,具体该如何实现呢?

2、具体实现

我们的技术栈是 koa(服务端) + Vue.js(前端) 。有兴趣可以看这些资料:

在服务端,实现了一个token生成的中间件,koa-grace-csrf

  // 注意:代码有做精简
  
  const tokens = require('./lib/tokens');
  return function* csrf(next) {
    let curSecret = this.cookies.get('密文的cookie');
    // 其他如果要获取参数,则为配置参数值
    let curToken = '请求http头信息中的token';
    
    // token不存在
    if (!curToken || !curSecret) {
      return this.throw('CSRF Token Not Found!',403)
    }

    // token校验失败
    if (!tokens.verify(curSecret, curToken)) {
      return this.throw('CSRF token Invalid!',403)
    }

    yield next;

    // 无论何种情况都种两个cookie
    // cookie_key: 当前token的cookie_key,httpOnly
    let secret = tokens.secretSync();
    this.cookies.set(options.cookie_key, secret);
    // cookie_token: 当前token的的content,不需要httpOnly
    let newToken = tokens.create(secret);
    this.cookies.set(options.cookie_token, newToken)
  }

在前端代码中,对发送ajax请求的封装稍作优化:

  this.$http.post(url, data, {
      headers: {
          'http请求头信息字段名': 'cookie中的token'
      }
  }).then((res) => {})

总结一下:

  • Nodejs生成一个随机数,通过随机数生成散列密文;并将随机数和密文存到cookie;

  • 客户端JS获取cookie中的随机数,通过http头信息交给Nodejs;

  • Nodejs响应请求,校验cookie中的密文和头信息中的随机数是否匹配;

这里依旧有个细节值得提一下:Nodejs的上层一般是nginx,而nginx默认会过滤头信息中不合法的字段(比如头信息字段名包含“_”的),这里在写头信息的时候需要注意。

"One more thing..."

上文也提到,通过cookie及http头信息传递加密token会有很多弊端;有没有更优雅的实现方案呢?

1、cookie中samesite属性

回溯下CSRF产生的根本原因:cookie会被第三方发起的跨站请求携带,这本质上是HTTP协议设计的漏洞。

那么,我们能不能通过cookie的某个属性禁止cookie的这个特性呢?

好消息是,在最新的RFC规范中已经加入了“samesite”属性。细节这里不再赘述,可以参考:

  1. SameSite Cookie,防止 CSRF 攻击

  2. Same-site Cookies

2、更优雅的架构

当然,目前为止,客户端对samesite属性的支持并不是特别好;回到前后端分离架构下,我们明确下前后端分离框架的基本原则:

后端(Java / PHP )职责:

  • 服务层颗粒化接口,以便前端Nodejs层异步并发调用;

  • 用户状态保存,实现用户权限等各种功能;

前端(Nodejs + Javascript)职责:

  • Nodejs层完成路由托管及模板引擎渲染功能

  • Nodejs层不负责实现任何SESSION和数据库功能

我们提到,前端Nodejs层不负责实现任何SESSION和数据库功能,但有没有可能把后端缓存系统做成公共服务提供给Nodejs层使用呢?想想感觉前端整条路都亮了有木有?!这里先挖一个坑,后续慢慢填。

3、延伸

这里再顺便提一下,新架构下的XSS防御

犹记得,在狼厂使用PHP的年代,经常被安全部门曝出各类XSS漏洞,然后就在smaty里添加各种escape滤镜,但是添加之后发现竟然把原始数据也给转义了。

当然,现在更多要归功于各种MVVM单页面应用:使得前端完全不需要通过读取URL中的参数来控制VIEW。

不过,还有一点值得一提:前后端分离框架下,路由由Nodejs控制;我自己要获取的后端参数和需要用在业务逻辑的参数,在主观上前端同学更好把握一些。

所以, 在koa(服务端) + Vue.js(前端)架构下基本不用顾虑XSS问题(至少不会被全安组追着问XSS漏洞啥时候修复)。

总结

要不学PHP、看Java、玩Python做全栈好了?

查看原文

赞 28 收藏 109 评论 10

UioSun 赞了回答 · 2019-12-29

解决Laravel的Validator验证未通过时,错误信息中的 `:attribute` 如何替换为中文?

可以直接在validation.php这个文件中写的.比如:

return [
    'required'             => ':attribute 不能为空。',
    
    'attributes' => [
        'username' => '用户名',
    ]
];

通过这种方式就可以将:attribute替换成相应的中文了;

关注 5 回答 3

UioSun 赞了回答 · 2019-09-28

解决有没有在线SQL语句查询练习的平台

关注 9 回答 6

UioSun 发布了文章 · 2019-09-26

非开发编码集结

日常,练手,没查过是否最优解。
有更优解的朋友,欢迎留言怼我,感谢。

Days 2

:给定一个乱序的、纯数字的、值不重复的数组,请用递归,将其排序。
输入[12, 42, 5, 23, 65]
输出[5, 12, 23, 42, 65]

function quick_sort($array)
{
    if (count($array) > 1) {
        $array_left = [];
        $array_right = [];
        $base = array_pop($array);

        foreach ($array as $item) {
            if ($base < $item) {
                array_push($array_left, $item);
            } else {
                array_push($array_right, $item);
            }
        }
        $array_left = quick_sort($array_left);
        $array_right = quick_sort($array_right);

        return array_merge($array_left, [$base], $array_right);
    }

    return $array;
}

$array = [2, 6, 12, 3, 1, 9];
print_r(quick_sort($array));  /* Result is Array
(
    [0] => 12
    [1] => 9
    [2] => 6
    [3] => 3
    [4] => 2
    [5] => 1
).
*/

Days 1

:给定一个数字数组,请用递归,将其内部的值相加。
输入[2, 4, 6]
输出12

function sum($array)
{
    if (count($array) > 1) {
        return array_pop($array) + sum($array);
    }
    return $array[0];
}

echo sum([2, 6, 3, 1, 9]);  // Result is 21.

:给定数组与上题相同,请用递归,统计其内部值的个数。
输入[2, 4, 6]
输出3

function array_count($array)
{
    $count = 0;
    if ($array !== []) {
        array_pop($array);
        return ++$count + array_count($array);
    }
    return $count;
}

echo array_count([2, 6, 10, 3, 1, 9]);  // Result is 6
查看原文

赞 0 收藏 0 评论 0

UioSun 提出了问题 · 2019-05-24

解决对 Unique 约束,校对规则不区分大小写时,怎样存储区分大小写的值?

环境 MySQL 7,使用 InnoDB 表引擎。

对唯一性约束的字段,若字符集区分大小写,校对规则不区分大小写,能存储区分大小写的值吗?

希望能达到“区分大小写的存储用户昵称,并支持搜索时不区分大小写”,看着阿里、微博的搜索工具都能做到,好羡慕啊……

简单试了一下,没成功:

CREATE TABLE `test_one` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `test` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `test` (`test`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

# Succeed insert
INSERT INTO `test`.`test_one` (`test`) VALUES ('name');

# Error insert: "SQL Error (1062): Duplicate entry 'nAme' for key 'test'"
INSERT INTO `test`.`test_one` (`test`) VALUES ('nAme');

关注 2 回答 2

UioSun 赞了文章 · 2019-05-24

配置海康威视客户端软件 ivms-4200 实现服务端和客户端分离

版本: iVMS-4200(V3.3.0.7_C)

事情起于一个需求,公安部门要求门店重要位置的录像需要保存 3 个月,而这些位置比较重要,所以都是要保存完整录像而不能使用移动侦测的策略,现有硬盘录像机只有 4 个硬盘接口,每个接口接 4T 的硬盘,只能保存一个月,而这个硬盘录像机的接口只支持最大 6T 的硬盘,要满足需求就要把硬盘录像机和硬盘都更换,这样成本太高,也没有要开新店,能将换下来的设备重新利用.所以开始寻求其他的备份方案.

需求

  1. 能够通过网络备份录像
  2. 能够方便进行回放和浏览

解决方案

第一个想到的是用海康威视的存储服务器,只是当时装的 v2.7.2.4 版本的ivms-4200,这个版本只能在本地进行回放,这样如果有需要回放需要每次跑到机房,会很不方便,没法满足第二个需求.

第二个找到的方案是使用群晖的Surveillance Station套件,之前就一直在使用群晖作为ESXI的存储,实施起来也不是很困难,但是Surveillance Station不支持从硬盘录像机去取录像,只能从每个摄像头去读取流,监控网络使用的是百兆的交换机,如果直接去摄像头读取流的话,估计够呛,所以只是作为一个备选方案留着.

回头去逛了下海康威视的官网,发现新版本的ivms-4200,看了下手册,发现能够支持客户端和服务端分离,这样就能满足第二点需求了.

实施过程中的问题

不过在实施的过程中,出现了不少问题.

第一个问题是客户端没法单独安装和配置到指定的服务器.

服务端未开启或与客户端不在同一主机上,则登录客户端时,需要配置 IP 地址和端口。

这个是使用手册中的原文,但实际情况是安装客户端时总会将服务端安装上,而且就算把服务端退出,每次启动客户端的时候,都会自动启动服务端.咨询过官方客服,客服说把服务端的服务器自启动选项去掉,但是并不管用,这个选项是配置开机是否自启,而每当客户端启动的时候,服务端都会跟着启动.

最后通过把服务端的文件都删除,这样就不会启动服务端了.这时客户端提示连接超时,但是弹出的界面只能配置端口,而没有 ip 地址的配置.最后通过反复查看文档和翻设置项,发现有一个配置路劲的设置,找到这个路劲下(默认在C:\Users\Public\iVMS-4200 Site\UserData),有个Framework.C的文件夹里面的Setup.xml保存了客户端的配置,修改IPAddress的值为服务端的 ip 即可. 新版本中去掉了IPAddress字段,就算手动添加配置,也不管用了,只能连接本地的端口.这可以通过端口转发来实现,在客户端电脑上将本地端口映射到服务端.

# 将本地的 8080 端口转发到服务端的 1234 端口, 1234 对应这下面服务端的转发出来的端口
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=127.0.0.1 connectport=1234 connectaddress=127.0.0.1

这里会有第二个问题,客户端需要通过服务端的 HTTP 端口来连接服务端,坑爹的是这个服务端的其他端口是监听0.0.0.0的,而唯独 HTTP 端口是只监听 127.0.0.1,这个地址还没法配置,在Framework.SSetup.xml没有这个值的配置项,也许有只是没有地方去查也没招.最后想了一招,通过端口转发,将127.0.0.1:8080端口转发到另外一个端口开放出来,命令如下:

# 添加端口转发
# 这里的 listenport=1234 是开放的端口
# listenaddress=192.168.1.2 配置要监听的地址,可以写服务器本机的 ip,或者写 0.0.0.0
netsh interface portproxy add v4tov4 listenport=1234 listenaddress=192.168.1.2 connectport=8080 connectaddress=127.0.0.1

# 查看所有的端口转发
netsh interface portproxy show v4tov4

# 删除指定的端口转发
netsh interface portproxy del v4tov4 listenport=1234 listenaddress=192.168.1.2

这样通过服务器去存储录像,然后在客户机上安装客户端,有需要的时候,可以方便回放.算暂时满足需求,先用着,以后有更好的方案再说.

查看原文

赞 3 收藏 0 评论 6

UioSun 评论了文章 · 2019-04-12

180710-MySql插入唯一键冲突的三种可选方式

logo

MySql插入时唯一键冲突的几种处理方式

MySql插入一条记录,结果提示主键冲突,怎么办?

批量插入数据时,发现插入的这批数据中,有某些记录存在唯一键冲突,一个一个跳出来就比较麻烦了,有什么好的办法直接忽略掉冲突的记录么?

下面简单记录三种处理方式

<!-- more -->

I. 插入时唯一键冲突问题

1. Ignore关键词

某些场景下,我们需要批量插入的数据,某些已经在DB中了,因此我希望在出现冲突时,直接跳过,把能插入的都插入就好,这种情况下,使用ignore关键词就比较合适了

一个实际的case如下

insert ignore into table (xxx, xxx) values (xxx,xxx), (xxx, xxx);

执行截图如下, 注意下面红框中的内容,表示忽略了两条,执行插入成功一条

image.png

2. Replace Into方式

如果在批量插入中,存在冲突时,我希望用我的新数据替换旧的数据,这个时候就可以使用replace into

常用姿势如下

replace into `user` (`id`, `name`, `create_at`, `update_at`) 
values
    (1, 'test', '2018-07-10 18:54:00', '2018-07-10 19:54:52'),
    (2, 'test2', '2018-07-10 18:54:00', '2018-07-10 19:54:52'),
    (3, 'test3', '2018-07-10 18:54:00', '2018-07-10 19:54:52');

执行截图如下,注意红框中,当某条记录冲突之后并修改,则影响行数为2, 其实际过程是

  • 删除冲突数据
  • 插入新的数据

image.png

3. ON DUPLICATE KEY UPDATE

在出现冲突时,希望更新某些数据,这个时候就可以在insert语句的最后加上on duplicate key update

实例如下

insert into `user` (`id`, `name`, `create_at`, `update_at`) values (1, 'test0', '2018-07-10 18:54:00', '2018-07-10 18:54:52') ON DUPLICATE KEY UPDATE `update_at`='2018-07-10 19:58:05';

执行截图如下,这个是在原记录的基础上执行更新指定的value, 比如上面的插入中,当冲突时,我们只更新update_at字段,而name的test0没有更新

image.png

II. 其他

1. 一灰灰Bloghttps://liuyueyi.github.io/he...

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

3. 扫描关注

QrCode

查看原文

UioSun 关注了标签 · 2019-03-14

关注 55

UioSun 关注了标签 · 2019-03-14

game

Game可以指: 为PC或移动终端开发的娱乐性应用。

关注 7

认证与成就

  • 获得 76 次点赞
  • 获得 38 枚徽章 获得 0 枚金徽章, 获得 7 枚银徽章, 获得 31 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-06-14
个人主页被 1.4k 人浏览