豪翔天下

Change My World by Program

0%

安装方法

CentOS使用包的方式安装最新MariaDB,CentOS安装client直接yum install mysql而不是client,而安装mysql则直接用yum install -y mysql mysql-server mysql-dev mysql-devel,CentOS7上已经用mariadb代替了mysql,这样子使用:

1
2
3
4
5
6
7
8
9
10
yum install mariadb-server mariadb-client mariadb-devel -y
systemctl start mariadb.service # 启动服务
systemctl enable mariadb.service # 开机启动

# 彻底删除mysql
sudo systemctl stop mysql
sudo apt-get purge mysql-server mysql-client mysql-common mysql-server-core-* mysql-client-core-*
sudo rm -rf /var/lib/mysql
sudo rm -rf /etc/mysql
sudo deluser mysql && sudo delgroup mysql

另外,更新方式可以参考这篇文章: 如何更新到MariaDB 10.4

Ubuntu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装最新版本mariadb,需要先导入对应的镜像库https://downloads.mariadb.org/mariadb/repositories
sudo apt-get install mariadb-server mariadb-client libmariadbd-dev

## 安装mysql,可以使用https://dev.mysql.com/downloads/repo/apt/的方式
wget https://dev.mysql.com/downloads/repo/apt/mysql-apt-config_0.8.15-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.15-1_all.deb # 会进入版本选择界面,选择正确的版本,然后ok
sudo apt-get update && sudo apt-get install mysql-server即可

# 如果是开发,还需要安装
sudo apt-get install libmariadb-client-lgpl-dev
sudo ln -s /usr/bin/mariadb_config /usr/bin/mysql_config

# 第一次登录使用
sudo mysql # mysql8可以直接这样进入然后设置密码
sudo mysql -u root
阅读全文 »

安全测试

测试清单

对于用户可以控制的数据进行过滤或者转义处理

  • 包括get、post、cookie、header、数组下标等内容
  • 字符串必须对单引号进行转移处理,至少有”<”, “>”, “‘“, “””

    身份认证和会话管理

  • 加密的会话ID需要具有时效性,避免永不过期
  • 使用复杂的加密方式避免伪造
  • 避免每次生成同样的会话ID

    跨站脚本(XSS)

    功能级访问控制缺失

  • 对于每个功能的访问,需要明确授予特定角色的访问权限(在展示、修改、删除的时候必须检查信息的所有者和操作中是否一致,展示不同用户数据的时候尽量避免url参数可被遍历)

    跨站请求伪造(CSRF)

  • 关键请求必须增加来路判断
  • 关键请求尽量增加token校验(Token要足够随机,Token是一次性的)

    服务安全规范

  • 禁止外网服务使用默认配置
  • 禁止web应用通过IP方式访问
  • 禁止公网IP开放80和443以外的端口
  • 禁止.svn/.git/log等敏感文件发布到服务器,所有代码上传必须配置好过滤器
  • 禁止所有web应用目录写权限,如业务需要写权限必须禁止直行权限
  • 禁止数据库及非关系数据库服务器开放外网端口访问

代码审查清单

自己的代码审查清单,可以根据此来写测试

code方面

  • 代码能否正常工作,各个功能是否能得到正确的结果
  • 代码是否符合当前语言的编码规范,Python使用PEP8
  • 是否存在多余的代码和注释
  • 代码是否尽可能模块化了
  • 循环是否设置了终止条件
  • 是否有可删除的日志或调试代码

安全

所有的数据输入是否都进行了检查(检测正确的类型,长度,格式和范围)并且进行了编码?
在哪里使用了第三方工具,返回的错误是否被捕获?
输出的值是否进行了检查并且编码?
无效的参数值是否能够处理?

文档

是否有注释,并且描述了代码的意图?
所有的函数都有注释吗?
对非常规行为和边界情况处理是否有描述?
第三方库的使用和函数是否有文档?
数据结构和计量单位是否进行了解释?
是否有未完成的代码?如果是的话,是不是应该移除,或者用合适的标记进行标记比如‘TODO’?

测试

代码是否可以测试?比如,不要添加太多的或是隐藏的依赖关系,不能够初始化对象,测试框架可以使用方法等。
是否存在测试,它们是否可以被理解?比如,至少达到你满意的代码覆盖(code coverage)。
单元测试是否真正的测试了代码是否可以完成预期的功能?
是否检查了数组的“越界“错误?
是否有可以被已经存在的API所替代的测试代码?

全平台通用软件

  • Android Stuido:Android开发专用IDE
  • Bitwarden: 全平台还免费的密码管理工具
  • 百度云:把平时产生的垃圾文件都扔上面,重要信息以及其他文件加密上传
  • Docker:虚拟容器
  • FileZilla:有家庭免费版,FTP工具
  • Google Chrome: 最好的网页浏览器,没有之一
  • QQ
  • intelliJ IDEA(付费版本): 全栈开发必备,还能用来管理数据库
  • Postman: 最好用的http测试工具
  • SourceTree: Git项目管理工具
  • Sublime Text:编辑器,现在基本只用于快速打开大文本文件以及快速格式化文本文件用
  • VirtualBox:虚拟机应用
  • 微信
  • Wireshark:免费的抓包应用
阅读全文 »

正则表达式这个东西确实有点复杂,要是每次都从头写挺麻烦的,所以就把平时会用到的都记录到这儿。

  • 在线正则表达式测试以及性能分析工具:https://regex101.com/

  • 有一个搜索正则非常棒的方法,直接在google输入类似regex email等内容,出来的第一条会是谷歌提供的格式化的搜索结果。

  • 正则表达式引擎的实现方式:

    DFA自动机(Deterministic Final Automata确定型有穷自动机): 时间复杂度是线性的,更加稳定,但是功能有限

    NFA自动机(Non deterministic Finite Automaton不确定型有穷自动机): 时间复杂度不稳定,有时很好有时很差,大多数编程语言使用的是NFA,由于不稳定,所以对于复杂的语句我们有时候需要优化一下。

  • 正则匹配是一个CPU密集型的任务,如果出现CPU被占满性能依然不够的情况,可以用上述性能分析网站看是否有灾难性回溯的出现,如果没有,可以考虑换一种更适合业务场景的算法,例如敏感词过滤推荐使用DFA算法,最后,实在不行,只有提高CPU了。

字符 说明
^ 匹配字符串开始的位置
$ 匹配字符串结束的位置
* 零次或多次匹配前面的字符或子表达式,例如,zo*匹配z和zoo
+ 一次或多次匹配前面的字符或子表达式,例如zo+匹配zo和zoo但不匹配z
? 零次或一次匹配前面的字符或子表达式,例如zo?匹配z和zo但不匹配zoo
\w 匹配所有非特殊字符
\W 匹配所有特殊字符
[] 包括里面的字符
[^] 排除里面的字符
[^\W] 排除所有的非特殊字符
[\w]+或\w+ 匹配数字、字母以及下划线(即非特殊字符)
[\w-+]+ 匹配数字、字母、下划线以及-、+
{n} 刚好匹配n次,例如 o{2}与”Bob”中的”o”不匹配,但与”food”中的两个”o”匹配
{n,} 至少匹配n次
{n,m} 匹配至少n次,至多m次。不填m表示不限最大数量
. 匹配除”\n”之外的任何单个字符,要匹配任意字符应该使用([\s\S]*),这种方法包括了换行符的
.* 匹配任意字符,最长匹配(贪婪型的,比如(.)/就表示遇到最后一个/就结束)
.*? 匹配任意字符,最段匹配(贪婪型的,比如(.)/就表示遇到第一个/就结束),包括换行符就是([\s\S]*?)
?= 零宽断言,先从要匹配的字符串中的最右端找到第一个匹配项,然后再匹配前面的表达式,例如[a-z](?=ing)可以匹配cooking singing中的cook与sing,.(?=ing)可以匹配cooking singing中的cooking sing而不是cook,同样,这样的表达式可以匹配多次,适合找前缀和后缀的情况
\d 匹配一个数字
\n 匹配一个换行符
\f 匹配一个换页
\r 匹配一个回车符
\t 匹配一个制表符
\v 匹配一个垂直制表符
\s+ 匹配一个或多个空白
| 或者,最好把两个条件都用小括号括起来,例如(a|b)
() 在匹配的时候没什么作用,主要用于程序提取匹配到的字符串
(?i) 后面的内容忽略大小写
阅读全文 »

Python装饰器

装饰器就是一个函数,它接受其它函数为参数返回一个装饰过的函数,装饰器可用于静态方法、属性(@staticmethod),在函数前后执行特定代码(比如,验证参数、给函数调用做缓存、注册回调函数、给函数打日志)

最简单的装饰器:

1
2
3
4
5
6
7
8
9
10
11
from functools import wraps
def b(func):
@wraps(func)
def decorate(func):
print('b')
return func(canshu) # 如果要传递参数可以在这里进行传递
return decorate

@b
def a(canshu):
print('a')

执行a()的时候会分别输出ba,需要注意的是,这里不加wraps也是可以的,但是如果不加wraps,那么函数就真的相当于一个新的函数了,通过内省方法获取函数的元信息等都会变成新的,而如果wraps则会消除这样的影响。在flask中如果对views函数进行了装饰,不加wraps会出现这样的错误:

AssertionError: View function mapping is overwriting an existing endpoint function: decorate

使用类作为装饰器

被装饰的函数会作为实例化参数,得到一个类实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class LoginCheck:
def __init__(self, f):
self._f = f

def __call__(self, *args):
Status = check_function()
if Status is 1:
return self._f(*args)
else:
return alt_function()

def check_function():
return test

def alt_function():
return 'Sorry - this is the forced behaviour'

@LoginCheck
def display_members_page():
print 'This is the members page'

应用场景

  1. 日志记录与分析
  2. 数据验证(用户合法性校验、数据合法性校验)
  3. 重复使用代码

Git指南

这里所列举的通用配置无论是在Windows还是Linux,都要用到。

  • 一定一定要设置好nginx或者apache的权限,保护好.git目录,防止被黑客获取到,因为这个目录下的文件包含了所有的文件内容,例如:

    1
    2
    3
    4
    5
    6
    import zlib
    import requests

    url = "https://domain/.git/objects/9d/6d1ae673f15900b8efd9ad875364b3a651cc0e"
    re = requests.get(url)
    content = zlib.decompress(re.content) # 这就是文件内容

安装与配置

安装Git软件

Windows平台:Git for Windows(在安装的时候注意那些选项的设置)

Linux平台:sudo apt-get install git

基础配置

打开终端,在windows平台就用上一步安装上的git bash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 全局配置,这里的用户名和邮箱填写你自己的帐号,可以是github上的帐号信息
git config --global user.name "haoflyent"
git config --global user.email "haoflynet@gmail.com"

# 如果要同一台机器多个git账户,那么可以取消全局设置
git config --global --unset user.name
git config --global --unset user.email
git config user.email "x@xx.com" # 在仓库里面单独设置
git config user.name "xx"
git config core.editor vim # 设置git的默认编辑器,不然在某些系统里面会用nano,不会用

# 生成密钥
ssh-keygen -t rsa -C "haoflynet@gmail.com"
# 然后一路默认就可以,注意看其中的密钥存放位置,其中公钥文件Windows默认为/c/Users/用户名/.ssh/id_rsa.pub# Linux默认为 ~/.ssh/rsa_pub
阅读全文 »

fpm打包工具

安装过程

1
2
3
4
yum install -y rpm-build ruby-devel virtualenv gcc
pip install virtualenv-tools
gem install -V fpm
fpm -h

常用参数

  • -a: 架构名称,值可以为 x86_64
  • –config-files: 指定配置文件,可以指定多个。需要注意的是并不是所有文件都适合以配置文件的方式放入包中,不要将动态的文件放入配置文件中
  • -d ‘名称’: 指定程序依赖,多个依赖的话就写多个-d
  • –debug:打印编译时的详细日志
  • -C: 指定在打包前需要进入的目录(打包时的相对路径),相当于把那个目录打包
  • -n: 包名
  • -s: 源的类型,值可以为dir,rpm,gem,python,virtualenv,empty,tar,deb,cpan,npm,osxpkg,pear,pkgin,zip
  • -t: 目标类型,值可以为rpm,deb,solaris,puppet,dir,osxpkg,p5p,puppet,sh,solaris,tar,zip
  • -epoch 0,比-v更优先级的一个版本号
  • -v: 版本号,例如1.0.0
  • –iteration 1: 比-v更低优先级的一个版本号
  • –rpm-dist el7: 定义系统的迭代版本,el6表示centos6el7表示centos7,会生成在包名中,例如: example-0.1.0-el7.x86_64.rpm
  • –before-install, –pre-install 名称.sh: 安装前执行的脚本
  • –after-install, –post-install 名称.sh: 安装后执行的脚本
  • –before-remove, –pre-uninstall 名称.sh: 卸载前执行的操作
  • –after-remove, –post-uninstall 名称.sh: 卸载后执行的操作
  • -p, –prefix=目录: 指定软件之后要安装的路径
  • –description ‘这里写描述’
  • –url: 软件的网官网
  • –license ‘2-clause BSD-like license’:
  • –vendor: 供应商名称
  • –verbose: 打印详细安装过程
  • -m, –maintainer: 维护者
  • –rpm-sumarry: 简介
  • –description: 详情
  • usr=/,以这种方式,可以直接将当前目录下的目录在打包后放到指定的目录,例如,这里将工程目录下的uer目录放到了打包后的根目录,这样usr下的所有文件或文件夹都会被递归地打入包中。

以Virtualenv的方式打包Python包

相比与-s python的方式,将源设置为virtualenv(即-s virtualenv)的好处是不会破坏系统本身的python环境,不会与已经安装的包或者其他程序依赖的包产生冲突。举例,有一个需要打包的python包源码目录结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.
├── Pipfile # 自己开发时使用的是pipfile进行依赖管理,当然对fpm打包没有影响
├── Pipfile.lock
├── README.md
├── etc # 一些典型的配置文件
│   ├── logrotate.d # 日志轮转配置文件
│   │   └── my-agent
│   ├── rc.d # 系统服务配置文件,该文件编写方式有点特殊,可以去谷歌一下
│   │   └── init.d
│   │   └── my-agent
│   └── my-agent # 程序本身配置文件
│   └── default.conf
├── usr # lib文件默认会被加入/usr/lib中,所以,这里直接以目录树形式存储
│   └── lib
│   └── my-agent
│      └── agent.state
├── scripts
│   ├── my-agent-after-install.sh
│   └── my-agent-before-remove.sh
├── setup.py # 正常打python egg包所需要的文件,里面定义了包的一些元信息
└── src # 程序源码
├── xxx.py
└── __init__.py

然后使用这样的命令进行打包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fpm \
--debug \
-s virtualenv \ # 指定以virtualenv的形式进行打包
-t rpm \
-n my-agent \
-a 'x86_64' \
-v 0.1.0 \
--license '2-clause BSD-like license' \
--vendor 'Hao inc.' \
--category 'System Environment/Daemons' \
-m 'haofly' \
--config-files etc/my-agent/default.conf \
--config-files etc/logrotate.d/my-agent \
--config-files etc/rc.d/init.d/my-agent \
--after-install ./scripts/my-agent-after-install.sh \
--before-remove ./scripts/my-agent-before-uninstall.sh \
--url 'https://haofly.net' \
--rpm-summary 'rpm summary.' \
--description 'package description' \
--prefix /usr/share/my-agent \ # 指定安装目录,如果不指定会默认安装到/usr/share/python/下面
.

其他相关命令

1
2
rpm localinstall 包名 # 在新的机器上安装该软件
rpm -qpl 包名 # 查看包的信息

打包nginx例子

这是我打包tengine的命令fpm -s dir -t rpm -n tengine -v 2.1.2 -C /etc/nginx -d 'pcre-devel' -d 'openssl' -d 'openssl-devel' --before-install /share/before-install.sh --after-install /share/after-install.sh --before-remove /share/before-remove.sh --after-remove /share/after-remove.sh --description 'Haofly first fpm package' --url 'http://haofly.net' --prefix=/etc/nginx

安装

CentOS 6.4安装phpMyAdmin

Ubuntu安装

1
2
3
4
# apache
sudo apt-get install phpmyadmin apache2-utils
## vim /etc/apache2/apache2.conf,添加如下一行
Include /etc/phpmyadmin/apache.conf

连接多个主机的配置

参考文章
配置如下:

  1. 将phpMyAdmin根目录下的config.sample.inc.php,重命名为config.inc.php

  2. 修改config.inc.php文件,添加如下内容:

     $connect_hosts = array(
         1 => array(
             "host"    => "127.0.0.1",
             "port"    => "3307",
             "socket"=> "/tmp/mysql.sock2",
             "user"    => "root",
             "password"    => "mysql",
             "connect_type"    => "socket"
             ),
         2 => array(
             "host"    => "127.0.0.1",
             "port"    => "3309",
             "user"    => "root",
             "password"    => "mysql",
             "connect_type"    => "tcp"
             )
         );
    
     for ($i=1;$i<=count($connect_hosts);$i++){  
         $cfg['Servers'][$i]['auth_type'] = 'cookie';  
         $cfg['Servers'][$i]['host'] = $connect_hosts[$i]['host'];   //修改host  
         $cfg['Servers'][$i]['connect_type'] = $conenct_hosts[$i]['connect_type'];  
         $cfg['Servers'][$i]['port'] = $connect_hosts[$i]['port'];
         if (array_key_exists('socket', $connect_hosts[$i])){
         $cfg['Servers'][$i]['socket'] = $conenct_hosts[$i]['socket'];
         }
         $cfg['Servers'][$i]['compress'] = false;  
         $cfg['Servers'][$i]['extension'] = 'mysql';  
         $cfg['Servers'][$i]['AllowNoPassword'] = true;  
         $cfg['Servers'][$i]['user'] = $connect_hosts[$i]['user'];  //修改用户名  
         $cfg['Servers'][$i]['password'] = $connect_hosts[$i]['password']; //密码  
         $cfg['Servers'][$i]['bs_garbage_threshold'] = 50;  
         $cfg['Servers'][$i]['bs_repository_threshold'] = '32M';  
         $cfg['Servers'][$i]['bs_temp_blob_timeout'] = 600;  
         $cfg['Servers'][$i]['bs_temp_log_threshold'] = '32M';  
     }
    
  3. 重启apache

TroubleShooting

  • 如果出现#2002 无法登录 MySQL 服务器错误,可能是地址填写的是localhost而不是127.0.0.1所致

SaltStack

salt-minion是可以在单价运行的,相当于就在本机运行,以masterless方式运行。
master需要开启4505和4506端口

安装

# 服务器端
rpm -Uvh --force
取消/etc/salt/master里面的注释interface: 0.0.0.0

# 客户端
vim /etc/salt/minion
master: salt 取消注释,这里写master的地址
id:     # 指定ID,如果不指定,默认应该是hostname
log_file: /var/log/salt/minion # 取消注释,打开日志
key_logfile: /var/log/salt/key # 取消注释,打开日志

# 重启两个端过后
在master端执行:
salt-key -L     # 查看是否有证书签发请求
salt-key -a 刚才查出来的ID # 同意签发证书

# 测试,在master执行一条命令
salt '刚才的id' cmd.run 'hostname'

创建state

# 首先得有一个/srv/salt/top.sls,这是必须的
base:                # 相当于仓库
  '*':                # 对象名,*表示所有的minion
    - webserver    # 自定义的资源名

# 针对上面定义的每一个资源需要有相应的配置文件,例如/srv/salt/webserver.sls,以下配置来自http://blog.sctux.com/?p=278
apache:                # 自定义的资源ID
  pkg.installed:        # 包管理方式安装下面的包
    - names:
      - httpd
      - httpd-devel
  service.running:    # 模块名
    - name: httpd    # 要启动的service
    - enable: True    # 开机启动
    - reload: True    # 监视下面的文件,如果有变动就重启
    - watch:
      - file: /var/www/html/index.html
    - require:
      - pkg: httpd    # 启动服务的前提是有这个包
  file.managed:        # 模块名
    - name: /var/www/html/index.html    # 目的文件
    - source: salt://index.html        # 源文件
    - user: apache                        # 文件所有者
    - group: root
    - mode: 644
    - backup: minion                    # 改变之前备份
    - require:
      - pkg: httpd

# 官网提供的另外的写法
apache:
  pkg:                # 声明state
    - installed        # 声明函数

常用命令

# 执行远程命令
salt '目标' <function> [arguments]
salt '*' test.ping    # ping一下所有的主机
salt -G 'os:Ubuntu' test.ping # 可以指定某一种系统
salt -E 'virtmach[0-9]' test.ping # 还能使用正则
salt -L 'foo,bar,baz,quo' test.ping    # 多个minion
salt -C 'G@os:Ubuntu and webser* or E@database.*' test.ping    # 反正就是想要的语法都有

# 系统自带的函数
salt '*' sys.doc
salt '*' test.ping
salt '*' cmd.run 'uname -a'    # 这就是执行命令
salt '*' cmd.exec_code python 'import sys; print sys.version'
salt '*' pip.install salt timeout=5 upgrade=True
salt '*' state.highstate # 将配置发往minion