苏苏的博客

简约至极

在Android上运行PHP

为安卓交叉编译ARM版的PHP

本教程操作都在centosdocker容器内.基本工具都类似.

yum update && yum upgrade && yum install wget make perl -y 不用安装gcc

  1. 下载交叉编译工具 https://pan.baidu.com/s/1micZBWc

直连下载 wget http://share.suconghou.cn/files/arm/crossx86-arm-linux-musleabi-1.1.12.tar.xz

下载后解压,并添加bin到环境变量tar Jxf crossx86-arm-linux-musleabi-1.1.12.tar.xz

export PATH=/arm-linux-musleabi/bin:$PATH

之后,使用arm-linux-musleabi-gcc -v 可以验证

  1. 修改musl-libc库,目的是修改查找的DNS配置文件.
cd /tmp && wget --no-check-certificate https://www.musl-libc.org/releases/musl-1.1.16.tar.gz

下载并解压tar zxf musl-1.1.16.tar.gz && cd musl-1.1.16

替换1: 替换/etc/resolv.conf

grep -rn "/etc/resolv.conf" . 即可查找到有两个文件包含它.

接下来,我们把它替换掉,把路径替换为安卓安装文件夹可写的路径

sed -i "s{/etc/resolv.conf{/data/data/cn.suconghou.hello/files/resolv.conf{" ./src/network/resolvconf.c
sed -i "s{/etc/resolv.conf{/data/data/cn.suconghou.hello/files/resolv.conf{" ./include/resolv.h

可以再次查找,以验证是否替换成功

替换2: 替换/etc/hosts

grep -rn "/etc/hosts" . 即可查找到有三个文件,其中有一个是注释 下载执行替换,同样替换为一个我们可以写入的路径

sed -i "s{/etc/hosts{/data/data/cn.suconghou.hello/files/hosts{" ./src/network/getnameinfo.c
sed -i "s{/etc/hosts{/data/data/cn.suconghou.hello/files/hosts{" ./src/network/lookup_name.c

再次查找以验证是否替换成功

替换3: 替换/bin/sh,使我们可以使用android的sh

grep -rn "/bin/sh" . 即可查找到较多结果,我们需要修改

./include/paths.h

./src/legacy/getusershell.c

./src/misc/wordexp.c

./src/process/system.c

./src/stdio/popen.c

这5个文件

sed -i "s{/bin/sh{/system/bin/sh{" ./include/paths.h
sed -i "s{/bin/sh{/system/bin/sh{" ./src/legacy/getusershell.c
sed -i "s{/bin/sh{/system/bin/sh{" ./src/misc/wordexp.c
sed -i "s{/bin/sh{/system/bin/sh{" ./src/process/system.c
sed -i "s{/bin/sh{/system/bin/sh{" ./src/stdio/popen.c

同样可以再次查找验证是否替换.

然后开始编译我们修改后的musl

./configure --prefix="/arm-linux-musleabi/arm-linux-musleabi" CC="arm-linux-musleabi-gcc"
make -j4 && make install

编译约需要5分钟,ls -lh /arm-linux-musleabi/arm-linux-musleabi/lib/ 这些文件就是编译后生成的新文件.

注意这里编译使用的是arm-linux-musleabi-gcc而不是gcc,事实上,从头到尾我们都不需要gcc

之后开始第三步,编译PHP

  1. 编译PHP

下载PHP最新源码,并解压

cd /tmp && wget http://php.net/distributions/php-7.1.8.tar.xz && tar xJf php-7.1.8.tar.xz && cd php-7.1.8

替换1: 同样,我们需要替换sh的路径, grep -rn "/bin/sh" . 有较多结果,我们需要替换./ext/standard/proc_open.c

sed -i "s{/bin/sh{/system/bin/sh{" ./ext/standard/proc_open.c

执行下面命令,把我们的编译命令都替换为交叉编译的命令

export HOST="arm-linux-musleabi"
export CC="arm-linux-musleabi-gcc"
export CXX="arm-linux-musleabi-g++"
export AR="arm-linux-musleabi-ar"
export LD="arm-linux-musleabi-ld"
export RANLIB="arm-linux-musleabi-ranlib"
export STRIP="arm-linux-musleabi-strip"
export CPPFLAGS="-I/deps/include"
export LDFLAGS="-L/deps/lib"
export SYSROOT_MUSL="/arm-linux-musleabi/arm-linux-musleabi"

我们先最小化编译PHP,生成Makefile

LDFLAGS="-static -L/deps/lib" CFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" CXXFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" ./configure --host=arm-linux-musleabi --enable-inline-optimization --enable-static=yes --enable-shared=no --without-pear --disable-cgi --disable-opcache --disable-fpm --disable-phpdbg --disable-all --enable-cli --enable-tokenizer

生成Makefile后,我们要修改Makefile使其静态编译.

sed -i "s{-I/usr/include{ {" Makefile
sed -i "s{-export-dynamic{-all-static{" Makefile

然后 make -j4 && make install 可以编译成功

原先的strip 命令,可以使用arm-linux-musleabi-strip代替

添加其他扩展需要我们自己下载编译,下面这个几个是编译CURL所必须的.

  1. zlib
cd /tmp && wget http://zlib.net/zlib-1.2.11.tar.gz
tar zxf zlib-1.2.11.tar.gz && cd zlib-1.2.11
CFLAGS="--sysroot=$SYSROOT_MUSL -Os" \
./configure \
--prefix=/deps \
--static
make && make install
  1. bz2
cd /tmp && wget http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
tar zxf bzip2-1.0.6.tar.gz && cd bzip2-1.0.6
# 把 Makefile 里 CFLAGS 里的 -O2 改为 -Os 后面的 -g去掉 , 前面几行gcc部分等写死的直接删除
make install PREFIX=/deps

这些删除

# To assist in cross-compiling
CC=gcc
AR=ar
RANLIB=ranlib
LDFLAGS=
  1. openssl
cd /tmp && wget https://www.openssl.org/source/openssl-1.0.2l.tar.gz
tar zxf openssl-1.0.2l.tar.gz && cd openssl-1.0.2l
CFLAGS="--sysroot=$SYSROOT_MUSL -static" \
./Configure \
linux-armv4 \
no-shared \
--prefix="/deps" \
--with-zlib-lib="/deps/lib" \
--with-zlib-include="/deps/include"
# 把 Makefile 里 CFLAG 里的 -O3 改为 -Os (vi 查找,第一个就是)
make && make install
  1. curl
cd /tmp && wget https://curl.haxx.se/download/curl-7.54.0.tar.gz
tar zxf curl-7.54.0.tar.gz && cd curl-7.54.0

CC="arm-linux-musleabi-gcc --sysroot=$SYSROOT_MUSL" \
CXX="arm-linux-musleabi-g++ --sysroot=$SYSROOT_MUSL" \
CPPFLAGS="-I/deps/include" \
LDFLAGS="-static -L/deps/lib" \
./configure \
--prefix="/deps" \
--enable-zlib \
--disable-shared \
--with-ssl="/deps" \
--enable-static \
--host=$HOST
# 把 Makefile 里 CFLAGS 里的 -O2 改为 -Os
make -j4 && make install

包含我们需要的一些扩展 , 然后编译PHP(上次编译后,需make clean)

这次我们指定php.ini的文件位置

--with-config-file-scan-dir=/data/data/cn.suconghou.hello/files/conf.d --with-config-file-path=/data/data/cn.suconghou.hello/files
LDFLAGS="-static -L/deps/lib" CFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" CXXFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" ./configure --with-config-file-scan-dir="/data/data/cn.suconghou.hello/files/conf.d" --with-config-file-path="/data/data/cn.suconghou.hello/files" --host=arm-linux-musleabi --enable-inline-optimization --enable-static=yes --enable-shared=no --without-pear --disable-cgi --disable-opcache --disable-fpm --disable-phpdbg --disable-all --enable-cli --enable-tokenizer --enable-session --enable-json  --enable-mbstring --enable-mbregex --enable-filter --enable-hash --enable-zip --enable-phar --with-sqlite3 --with-openssl=/deps --with-curl=/deps --with-zlib-dir=/deps

添加 --enable-zip --with-zlib-dir=/deps 启用zip和zlib扩展

--enable-pdo --with-pdo-sqlite --enable-sockets --enable-posix --enable-ftp

编译启用越多扩展,PHP进程的内存占用会稍微增加

同上面一样

生成Makefile后,我们要修改Makefile使其静态编译.

sed -i "s{-I/usr/include{ {" Makefile
sed -i "s{-export-dynamic{-all-static{" Makefile

然后 make -j4 编译,生成的文件在sapi/cli文件夹中,编译已经成功,由于这次启用了phar,make install时需要调用php命令Generating phar.php,但php可执行文件在Linux x86_64下无法执行,是arm环境的.因此不能执行make install,但编译是完好的.

使用arm-linux-musleabi-strip命令,可为我们编译的可执行文件瘦身.

最后编译的文件,能够运行于android2.2,服务于项目 https://github.com/suconghou/androidphp

问题

file_get_contents访问https时报错

file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed

这是由于证书引起的问题,使用curl访问可以正常访问.

使用下面语句可以查看openssl的默认证书配置

var_dump(openssl_get_cert_locations());

或者配置 file_get_contents 不验证https证书.

$stream_opts = [
    "ssl" => [
        "verify_peer"=>false,
        "verify_peer_name"=>false,
    ]
];

$response = file_get_contents("https://www.example.com", false, stream_context_create($stream_opts));

或者在 php.ini 中添加 openssl.cafile=/path/to/cacert.pem

证书下载 https://curl.haxx.se/ca/cacert.pem

git repo

使用gogs搭建git server

docker 方式安装

安装和运行docker就不说了.

1.首先docker pull gogs/gogs 拉取镜像

2.创建一个数据卷docker volume create --name gogs-data

要查看已有的数据卷,使用docker volume ls,数据卷用于保存数据,升级时数据不会丢,切勿删除此数据卷

3.启动服务

docker run -d --name=gogs --restart always -m 200m --log-opt max-size=2m  -p 10022:22 -p 10080:3000 -v gogs-data:/data gogs/gogs

使用-v gogs-data:/data挂载刚刚的数据卷,将数据卷内的数据映射到容器的/data路径下.

也可以前面添加一个nginx反向代理 /etc/nginx/conf.d/git.conf

server{
	listen 80;
	server_name git.xx.cn code.xx.cn;
	gzip on;
	gzip_min_length 1024;
	gzip_proxied any;
	gzip_comp_level 3;
	gzip_types text/plain text/javascript text/css text/json application/xml application/javascript application/x-javascript application/json;
	location / {
		client_max_body_size 10m;
		proxy_pass http://127.0.0.1:10080;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-Ssl off;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Port 80;
	}
}

4.升级

docker stop gogsdocker rm gogs 然后执行步骤3就可以了

不放心的话,可以先stop,然后rename,再步骤三启动新版本的,启动成功后再删除旧版本的.

5.数据备份与恢复

备份docker volume数据卷

文件接收端执行 nc -l 9090 > data.tar.gz 有些nc(busybox里的nc)可能是 nc -l -p 9090 > data.tar.gz

以只读模式挂载数据卷,挂载数据卷到/data路径

docker run --rm -it -v gogs-data:/data:ro busybox sh -c "cd /data && tar czvf - . | nc host 9090"

打包文件并发送到目标主机

恢复docker volume数据

如果没有这个数据卷,先创建数据卷 docker volume create --name gogs-data

docker run --rm -it -v gogs-data:/data busybox sh -c "nc -l -p 9090 | tar -C /data -zxf -"

然后通过宿主机发送数据 nc host 9090 < data.tar.gz

如果两台电脑可以直接连通

发送方 docker run --rm -it -v gogs-data:/data:ro busybox sh -c "cd /data && tar czvf - . | nc host 9090"

接收方 docker run --rm -p 9090:9090 -it -v gogs-data:/data busybox sh -c "nc -l -p 9090 | tar -C /data -zxf -"

相关错误

remote: Counting objects: 860, done.
remote: aborting due to possible repository corruption on the remote side.
fatal: protocol error: bad pack header

由于服务器端在传送 git pull 或者 git clone时需提前压缩数据,这些数据是存放在内存中.(git pull时服务端内存不断增长,由于我使用的docker,只分配了60M内存);当内存不够使用时造成错误.

解决方案 1. 增加服务端内存. 或者 2. 修改git客户端配置 https://stackoverflow.com/questions/4170317/git-pull-error-remote-object-is-corrupted

即客户端执行

git config --global pack.windowMemory "100m"
git config --global pack.SizeLimit "100m"
git config --global pack.threads "1"

顺便说 docker 修改内存配置

docker update gogs -m 200m --memory-swap=400m

配置网络转发

容器的http端口和ssh分别映射到1008010022,我们使用域名和80端口对外服务.

添加nginx配置 git.conf

server{
		listen 80;
		server_name git.ourwill.cn code.ourwill.cn;
		gzip on;
		gzip_min_length 1024;
		gzip_proxied any;
		gzip_comp_level 3;
		gzip_types text/plain text/javascript text/css text/json application/xml application/javascript application/x-javascript application/json image/jpeg image/gif image/png;
		location / {
				client_max_body_size 10m;
				proxy_pass http://127.0.0.1:10080;
				proxy_set_header Host $host;
				proxy_set_header X-Forwarded-Ssl off;
				proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
				proxy_set_header X-Forwarded-Port 80;
		}
}

少许优化:gogs默认没有gzip,我们通过nginx添加了gzip;设置最大提交文件为10M

然后就可以使用域名直接访问,如果发现通过nginx代理后报 502 nginx erro logPermission denied, 可能是SELinux的问题

检查SELinux日志 sudo cat /var/log/audit/audit.log | grep nginx | grep denied

如果发现被 SELinux拦截, 可以执行setsebool -P httpd_can_network_connect 1开启此条规则

附:

getsebool -a | grep httpd 可以查看 SELinux 关于 http 的配置

setsebool httpd_can_network_connect on 使本次生效

setsebool httpd_can_network_connect on -Ppersist模式,永久生效

使用后立即生效,无需重启任何服务.

配合git hook 自动部署PHP和静态网页

写了一个server用于接受通知 https://github.com/suconghou/gitsync.git

主要是接收到用户推送代码后,不存在则clone项目,存在则更新项目.

启动服务gitsy > /var/log/gitsy.log 2>&1 &,然后由nginx代理隐藏端口,使用域名访问

server{
    server_name g.share.ourwill.cn;
    listen 80;
    gzip on;
    location / {
        proxy_pass http://127.0.0.1:19090;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Ssl off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port 80;
    }
}

gitsy 启动后可通过http查看loghttp://g.share.ourwill.cn/log

repos目录可由docker挂载只读,防止删除操作,请求都转发到docker内,由内部nginx-fpm运行代码

转发到docker里的nginx

server{
    server_name *.share.ourwill.cn;
    listen 80;
    gzip on;
    index index.html index.php;
    location / {
        proxy_pass http://127.0.0.1:18001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Ssl off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port 80;
    }
}

docker目录的映射为docker run -v /data/share/runtime/:/www --name datafs busybox

docker run -d --name dev --restart always -m 100m --log-opt max-size=2m --volumes-from datafs -p 18001:80 -p 12201:22 suconghou/server

可以使用/data/share/runtime/:/www:ro使用只读

docker内部的nginx处理各个vhost的请求

server {
	listen  80;
	server_name 0.0.0.0;
	index index.html index.php;
	if ($host ~* ^(([\w\-]+)\.share\.ourwill\.cn)$) {
		set $subdomain $2;
	}
	root /www/$subdomain;
		if ( !-d $document_root ){
		return 404;
	}
	try_files $uri $uri/ /index.php?$args;
	location ~ \.php$ {
		try_files $uri =404;
		fastcgi_pass  127.0.0.1:9000;
		fastcgi_param debug 2;
		include        fastcgi.conf;
	}
}

也可以直接使用本地nginx+fpm请求,不使用docker,代码可本地读写

server{
	listen 80;
	server_name *.run.ourwill.cn;
	index index.php index.html;
	fastcgi_connect_timeout 2s;
	fastcgi_send_timeout 10s;
	fastcgi_read_timeout 5s;
	ssi on;
	gzip on;
	if ($host ~* ^(([\w\-]+)\.run\.ourwill\.cn)$) {
		set $subdomain $2;
	}
	root /data/share/runtime/$subdomain;
	if ( !-d $document_root){
		return 404;
	}
	add_header X-Root "$subdomain";
    try_files $uri $uri/ /index.php?$args;
	location ~ \.php$ {
        try_files $uri =404;
        client_max_body_size 10m;
        fastcgi_param debug 2;
		fastcgi_pass 127.0.0.1:9000;
        include        fastcgi.conf;
	}
}

此两种环境都传递了变量 debug 到php-fpm,php 代码中可使用 getenv('debug') 判断是何种环境.线上环境没有配置debug,得出false

lego and acme to enable https

acme

https://github.com/Neilpang/acme.sh

https://github.com/xenolf/lego

lego使用golang编写,acme.sh使用bash编写;使用都非常方便

使用lego签发证书

签发证书之前,确保要签发的域名的解析是指向当前要运行lego服务器的IP

签发过程中,lego需要监听80443端口,请确保有权限且未被占用.

证书的签发使用的当前服务器的IP和后续证书的使用没有关系

一次生成包含多个域名的证书.

./lego --email="suconghou@126.com" --domains="g.suconghou.cn" --domains="share.suconghou.cn" --domains="play.suconghou.cn" --domains="go.suconghou.cn" run

运行成功无报错的话,将会在目录下生成.lego目录,里面存放证书

生成的 域名.crt 文件 和 域名.key 文件

key文件即为nginx中ssl_certificate_key需配置的文件. 被称为 证书密钥

.crt 文件即为nginx中ssl_certificate需配置的文件. 有的也称 fullchain.cer 被称为 授权证书

gcc

gcc 静态编译

1.c

#include <stdio.h>

void main()
{
	printf("hello");
}

gcc -static --verbose -fno-builtin 1.c

--verbose是为了输入编译的详细信息

-fno-builtin是阻止编译器把printf变成puts

如果出现错误

/usr/bin/ld: cannot find -lc
collect2: 错误:ld 返回 1

可能你还需要安装glibc的静态库

yum update && yum install glibc-static -y

优化选项

https://www.zhihu.com/question/27090458

gcc -static -O  1.c
gcc -static -O2 1.c
gcc -static -O3 1.c
gcc -static -Os 1.c

错误提示

-pedantic编译选项并不能保证被编译程序与ANSI/ISO C标准的完全兼容,它仅仅只能用来帮助Linux程序员离这个目标越来越近。或者换句话说,-pedantic选项能够帮助程序员发现一些不符合 ANSI/ISO C标准的代码,但不是全部,事实上只有ANSI/ISO C语言标准中要求进行编译器诊断的那些情况,才有可能被GCC发现并提出警告。

除了-pedantic之外,GCC还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W开头,其中最有价值的当数-Wall了,使用它能够使GCC产生尽可能多的警告信息。

gcc -Wall test.c -o test

GCC给出的警告信息虽然从严格意义上说不能算作错误,但却很可能成为错误的栖身之所。一个优秀的Linux程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮的特性。所以将警告信息当成编码错误来对待,是一种值得赞扬的行为!所以,在编译程序时带上-Werror选项,那么GCC会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改,如下:

gcc -Werror test.c -o test

调试选项

1) -g选项,产生供gdb调试用的可执行文件:gcc -g helloworld.c

产生一个叫作a.out的可执行文件,大小明显比只用-o选项编译汇编连接后的文件大。

2) -pg选项,产生供gprof剖析用的可执行文件:gcc -pg helloworld.c

产生一个叫作a.out的执行文件,大小明显比用-g选项后产生的文件还大。

https://www.systutorials.com/5217/how-to-statically-link-c-and-c-programs-on-linux-with-gcc/

LDFLAGS=-static ./configure --disable-plugins=auth,cgi,cheetah,dirlisting,fastcgi,liana,logger,mandril,tls --malloc-libc

编译更小的文件

gcc 使用参数 -Os -ffunction-sections -fdata-sections link 的时候使用 --gc-sections

-ffunction-sections, -fdata-sections会使compiler为每个function和data item分配独立的section。 –gc-sections会使ld删除没有被使用的section。

链接操作以section作为最小的处理单元,只要一个section中有某个符号被引用,该section就会被放入output中。

这些选项一起使用会从最终的输出文件中删除所有未被使用的function和data, 只包含用到的function和data

export CFLAGS=“-Os -ffunction-sections -fdata-sections” export LDFLAGS=“-Wl,–gc-sections”

然后 对可执行文件 strip -s

系统安全

Nginx安全配置

如果你是用git或者svn来部署代码,默认情况下,你的网站很可能已经泄露了.git目录,或者.svn目录

使用nginx配置过滤一切以.开头的文件和文件夹,防止被用户下载.

location ~ /\. {
	deny all;
}

每个网站都需要这么配置可能有些麻烦,你可以在统一的文件中定义好/etc/nginx/default.d/php.conf

listen 80;
index index.html index.php;
try_files $uri $uri/ /index.php?$args;
location ~ /\. {
	deny all;
}
location ~ ^.+\.php$ {
	try_files $uri =404;
	fastcgi_pass 127.0.0.1:9000;
	include fastcgi.conf;
}

使用时,类似与下面,还不用每次写这么多配置了.

server{
  server_name fed-wx.xxx.cn;
  root /data/www/fed-wx;
  include /etc/nginx/default.d/php.conf;
}

给http段添加,开启一些gzip特性,关闭显示服务器版本

default_type        application/octet-stream;
sendfile            on;
tcp_nopush          on;
tcp_nodelay         on;
keepalive_timeout   65;
types_hash_max_size 2048;
server_tokens off;
ssi on;
gzip on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 3;
gzip_types text/plain text/javascript text/css text/json application/xml application/javascript  application/json image/jpeg image/gif image/png;

修改你的SSH默认端口,并且使用强密码

每天都有大量的端口扫描来扫描你服务器IP的22端口,如果你的22端口密码又不强,很可能已被黑客侵入.

如果发现已经有大量的错误登陆,请立即更换端口.必要时考虑使用fail2ban

所有的网络通信都应该使用HTTPS

http并不安全,很有可能你收到和发出的信息,已被中间人劫持.

中间人劫持能查看你发送的信息,修改返回给你的数据包.

为此,使用http时,务必加盐加密你的密码,以减少在传输过程中被窃取的可能.

更有效的是使用https来有效防止中间人劫持.

你的身份认证令牌应该多方关联.

即便使用https,你的身份认证令牌,一旦从其他渠道泄漏,黑客便能使用你的身份进行操作.

特别是具有管理员权限的身份令牌,更是会带来严重后果,在CSRF攻击中偷走令牌是常有的事.

因此你起码需要将cookie关键信息设置为httponlysecurity(使用https时),并小心过滤允许用户输入的链接地址(包含图片,视频地址)和富文本等. 必要时开启csrf-token认证.

还需要确保你的认证token在丢失以后也不能在黑客手中登陆.

这需要你在生成token时,进行多方关联,哈希时可包括IP地址,User Agent,当然用户ID也需要关联,这个token只能这个用户用.

服务器验证时并不是从token能找到用户,就验证通过,还需要对这些信息进行校验,验证还是不是那个客户端发出的.

除此之外,哈希时不能简单的哈希,还需要加盐哈希,防止黑客拆解出哈希包含的字段进而可以自己算出token.

即使黑客不能拆解你的哈希算法,也不知道哈希字段有哪些,只要他能捕获你发出的请求,(或窃取走你的token和所有可能参与哈希的字段),一样可以模拟请求,使用你的身份进行操作,除非你哈希时包含了IP. 因为来源IP黑客是无法模拟的,除非他和你在同一个外网出口IP路由下.

但如果客户的IP经常变动,IP参与哈希可能体验太不好了,于是还是回到最初的问题,

使用https,使用httponlysecurity的cookie,便能有效防止黑客捕获你的请求和偷走token

再加上token关联校验策略, 再加上token有效期滚动延期策略,三道屏障保护你的身份不被黑客冒用.

合适和正确的验证码

一上来就给用户弹验证码未免也太不友好了,合适的做法是账户最近连续3次登陆都是错误登陆再弹出高强度的验证码.

这很好实现,只需一个字段就能带来好的体验.

毕竟正常的用户大部分时间都是一次登陆成功.

用户使用过的验证码一定不能再次用来验证,要保证每次身份验证都是一个新的验证码.

不能拿一次对的验证码去重复尝试验证用户名,密码,否则等同于没有验证码.

即便使用了验证码,也是不可信的,现在的打码平台已近非常成熟了,简单的验证码也很容易做到机器识别了.

还应该限制用户登陆错误次数,一小时10次或一天30次不能再多了.

登陆和找回密码返回合适的信息

别再返回用户名不存在了,或者密码不正确

为了这一点点的客户体验,你将带来巨大的安全隐患.你的网站存在用户遍历漏洞.

黑客可以很轻松的知道一个用户有没有在你的网站注册.

黑客手中有大量的泄漏账户信息,一些有价值的账户就值得黑客深挖,通过此漏洞,黑客很容易找到哪些用户都有哪些账户.

更可怕的是,大部分人不同网站的密码是相同的.也许你的网站安全性很好,还使用了https,但是黑客只要攻破了防线最弱的那个网站拿到用户的密码,你所说的安全也就全瓦解了.

因此给出用户名或密码错误和找回密码每次都需要高强度验证码,并且返回如果你已注册,邮件已发送到您注册时的邮箱才是有效安全的方式.

可怕的撞库

大部分人不同网站的密码相同,作为使用者个人值得注意,需要为每个网站设置不同的密码,防止一个的密码泄露,其他网站的密码也不安全了.

作为系统设计者,也需要注意,最基本的密码不能明文存储,其次密码需要加盐存储.再者所有用户的盐不能都是一个,需要每个用户都有自己的盐.

做到即使被脱库,也不能直接得到密码,即使观测所有密文和盐,知道部分用户的明文密码,也不能拆解出其他用户的明文密码.(这就需要每个用户有自己的盐)

密文切记不要直接md5,或者md5加固定盐.这些都已不在安全.

修改关键信息时必须验证

为避免黑客盗取了身份认证信息,冒用正常用户,去修改邮箱,手机号等关键信息.

在修改之前一定需要二次验证.

否则手机号被修改,您账户里的财产在做变动时,验证码就发送到黑客修改过的手机上了,黑客顺利成章的就完成了交易.

邮箱和手机号已不在是有效凭据

即使使用手机号和邮箱来标示一个用户,那也不一定是正确的.

目前黑市上已经有很多成熟的产业链,黑客花少量的钱就能很快拥有数以万计的手机号和邮箱,能便捷的发送和接收验证码.

有利可图的地方就有黑客存在,在发放红利时须倍加小心.

手势解锁安全吗

大部分的手势解锁都是靠次数和时间限制,但是程序在客户端,黑客很容易修改程序配置文件,达到无限次尝试.

并且手势密码的验证大部分都是本地验证,意味着黑客根本不需要与服务器端交互,有很多方式攻破程序里的本地认证

因此手势密码只防君子,不妨小人,不要把它作为十分安全的验证,在做敏感操作时务必联网验证用户密码.

音乐标题
歌手