金氧

敏感数据处理

背景

大多数应用或多或少都会涉及到敏感数据处理,比如用户的手机号、身份证号,甚至银行卡账号。作为应用的开发者,如何 安全地 维护这些敏感数据呢?

这里讨论的安全不是指服务器如何保护,而是在数据库层面做敏感数据的分离:

  • 业务库中不保存敏感数据,只保存混淆过的数据,比如电话字段保存的是 133****9961,在数据层面就进行脱敏
  • 敏感数据统一保存在另一个库中,有应用调用一个服务来建立原值和混淆值的映射关系
  • 业务库中因为保存的是脱敏过的数据,通过只读复制镜像可以很方便地提供给其他服务使用,比如 OLAP
  • 除了技术开发上方便,运维上也方便了很多,降低了敏感数据被暴露到外部的可能性

技术设计

提供服务接口给应用存取敏感数据,本质上是一个 KV 存取服务。

4910a7b5389945cc870dcc8f9cbfaf88

一些细节:

  • 表 protyle 的 domain 字段用于标识该记录的作用域,在一个作用域上相同的值要保证唯一
  • 表 protyle 的 hash 字段值是 SHA-512(domain/value) 的结果,用于唯一性校验

移动端数据库新王者:realm

介绍

realm是一个跨平台移动数据库引擎,支持iOS、OS X(Objective‑C和Swift)以及Android。
2014年7月发布。由YCombinator孵化的创业团队历时几年打造,是第一个专门针对移动平台设计的数据库。目标是取代SQLite。
为了彻底解决性能问题,核心数据引擎用C++打造,并不是建立在SQLite之上的ORM。如果对数据引擎实现想深入了解可以查看:Realm 核心数据库引擎探秘。因此得到的收益就是比普通的ORM要快很多,甚至比单独无封装的SQLite还要快。
因为是ORM,本身在设计时也针对移动设备(iOS、Android),所以非常简单易用,学习成本很低。

碾压级性能
数据引自:introducing-realm
每秒能在20万条数据中进行查询后count的次数。realm每秒可以进行30.9次查询后count。

在20万条中进行一次遍历查询,数据和前面的count相似:realm一秒可以遍历20万条数据31次,而coredata只能进行两次查询。

一次事务每秒插入数据的对比,realm每秒可以插入9.4万条记录,在这个比较里纯SQLite的性能最好,每秒可以插入17.8万条记录。然而封装了SQLite的FMDB的成绩大概是realm的一半。

解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题

MWPhotoBrowser是一个非常不错的照片浏览器,在github的star接近3000个。

MWPhotoBrowser来加载小图1M以下的都应该不会有内存警告的问题。如果遇到大图,3M、4M、5M的大图,很有可能导致内存警告。最近我就遇到这个问题,很是头疼。来回滑动查看照片内存飙到100M以上。

网上查了很多资料,都没有解决问题。

我们来看一下MWPhotoBrowser,其实MWPhotoBrowser用的是SDWebImage来下载图片的。

在github看到SDWebImage的介绍,后面说到:

Future Enhancements
LRU memory cache cleanup instead of reset on memory warning

看到这个真是欲哭无泪啊。

gitconfig配置别名alias

git有一些命令如:git pull 、 git push等等,这些命令可以设置alias,也就是缩写。如:git pull 是 git pl, git push 是 git ps。可以根据个人习惯进行修改。

修改别名alias步骤如下:

1,进入根目录

$ cd

2,查看根目录下面的文件

$ ls -la

查看一下有没有.gitconfig文件。

3,编辑.gitconfig

$ vi .gitconfig

添加如下:

[alias]
co = checkout
ci = commit
st = status
pl = pull
ps = push
dt = difftool
l = log --stat
cp = cherry-pick
ca = commit -a
b = branch

具体可以根据个人习惯进行添加修改。

你保存用户密码的姿势正确吗?

摘要

这几年陆陆续续有很多大站被脱裤,最终导致了很多用户的密码明文泄露。本文不探讨脱裤技术,主要研究的是如何正确(尽量安全)地保存用户密码。

哈希

“把明文加密后再保存数据库”应该是大家的共识。这个过程应该是不可逆的(不能通过加密后的串再得到原文),所以对于这个“加密”过程更贴切的叫法应该是 - 哈希:

Hash,一般翻译做“散列”,也有直接音译为“哈希”的。就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。
这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。
简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

我们常用的 Hash 算法主要就是 MD5 和 SHA,并且很多时候我们就是使用其中一种来加密用户密码的。
以上两类哈希算法主要是用于校验文件/数字签名,但并不适合用来保护用户密码,虽然对于我们来说_感觉上_似乎起到了一定安全防护的效果,但其实效果很差,特别是 MD5,秒秒钟就可以找到碰撞值。

iOS开发之如何跳到系统设置里的各种设置界面

需求

从应用跳到系统设置里的WiFi界面有这个需求存在吗?答案是肯定的。比如以下两个例子:

在没有网的状态下,你可能想提醒用户去设置界面连接WiFi。如果不能跳到WiFi界面,只能在APP里面做出文字提示。这样很多小白用户可能不会看提示,只会觉得APP没有做好。

还有一种情况,做智能家居的APP,智能硬件设备自带WiFi(局域网)。如果用户没有连接设备的WiFi进入APP时,需要提示用户去设置界面连接WiFi。

以上这两种情况只是举个例子,这个小功能的用处还是很多的,大家可以自行探索。

实现

info里面设置

在项目中的info.plist中添加 URL types 并设置一项URL Schemes为prefs,如下图:

wifi1

实现代码

NSURL *url = [NSURL URLWithString:@"prefs:root=WIFI"];
if ([[UIApplication sharedApplication] canOpenURL:url])
{
    [[UIApplication sharedApplication] openURL:url];
}

Carthage去中心化的Cocoa依赖管理器

说到 iOS 的依赖管理工具,大家一定首先想到的是 CocoaPods ,不错,CocoaPods 确实是一个很好依赖管理工具,已然成为了 Cocoa 依赖管理的标准,丰富的支持库、文档等等,CocoaPods 相关的文章有很多,这里就不一一赘述了。

今天要介绍的是一款新的依赖管理工具,名曰 “Carthage”,名字有点难理解,简单方便,完全独立,不修改 XCode 项目文件或配置。我们已经有了CocoaPods,非常好用,那么为什么还要创建这样一个项目呢?本文翻译自Carthage的Github的README.md,带大家来了解一下这个工具有何不同之处。

Carthage的目标是用最简单的方式来管理Cocoa第三方框架。

基本的工作流如下:

  1. 创建一个Cartfile,包含你希望在项目中使用的框架的列表
  2. 运行Carthage,将会获取列出的框架并编译它们
  3. 将编译完成的.framework二进制文件拖拽到你的Xcode项目当中

Carthage编译你的依赖,并提供框架的二进制文件,但你仍然保留对项目的结构和设置的完整控制。Carthage不会自动的修改你的项目文件或编译设置。

禁止浏览器自动填充表单字段

场景

我们的登录表单一般都是 input text + input password:

<form id="loginForm">
    <input type="text" name="username">
    <input type="password" name="password">
    <button type="submit">登录</button>
</form>

登录后如果用户选择了保存登录密码,那后续界面中如果有形如:

<input type="text" name="field1">
<input type="password" name="field2">

这样的两个 input(text+password)接在一起,那浏览器就会自动填充登录时的输入。

要用程序清空自动填充有两个方案:

使用 autocomplete 属性

在不需要自动填充的 input 上设置 autocomplete 属性:

<input autocomplete="off">

这个方案对于某些版本的浏览器可能不行。

使用假的 input 让浏览器去填充

在页面 后加入:

<!-- fake fields are a workaround for chrome autofill getting the wrong fields -->
<input style="display:none" type="text" name="fakeusernameremembered"/>
<input style="display:none" type="password" name="fakepasswordremembered"/>

这个方案原理是让浏览器去填充用户实际上看不到的 input。虽然看上去代码比较 low,但是很实用。

参考:Disabling Chrome Autofill

标签服务实现漫谈

标签服务是一个较为通用的基础业务服务,比如博客系统对文章加标签、社交网络中为好友添加印象、收藏的歌曲贴标签方便整理等等。

其主要提供两类接口:

  • 标签实体的管理/查询:负责标签实体的 CRUD
  • 标签关联的管理/查询:将外部业务实体与标签建立/删除关联,根据外部业务实体 id 查询标签集

理解 HTTPS 原理,SSL/TLS 协议

为什么要使用 HTTPS

当我们使用 HTTP 协议时,传输的数据是不安全的,因为所有在客户端和服务端往来的数据都是明文:

  • 第三方可以获取到真实数据
  • 第三方可以篡改数据
  • 第三方可以冒充服务端或客户端

为了解决这些问题,需要在 HTTP 协议中加入一个安全机制,由此并产生了 HTTPS,我们可以认为 HTTPS = HTTP + TLS/SSL。TLS/SSL 的引入解决了安全问题,而上层应用协议还是 HTTP。

www 开头的域名和 Cookie-free

Cookie-free, Cookie, www, SEO, 性能优化, 域名 2015-10-19
本文我们会探索两个问题:

  • 网站是应该选择 www 开头的域名作为用户入口还是应该使用不带 www 的域名(裸域)?
  • Cookie-free 是什么?为什么很重要?

PHP 异步 HTTP 与 NGINX 499

PHP 异步 HTTP

在 PHP 代码中提交异步 HTTP 请求比较常用的方式是通过 fsockopen/fwrite/fclose 来实现,请参考如下代码。

function post($host, $path, $port, $data) {
    $post = http_build_query($data);
    $len = strlen($post);

    $fp = fsockopen($host, $port, $errno, $errstr, 30);
    if (!$fp) {
        echo "$errstr ($errno)\n";

        return;
    }

    $out = "POST $path HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Content-type: application/x-www-form-urlencoded\r\n";
    $out .= "Connection: Close\r\n";
    $out .= "Content-Length: $len\r\n";
    $out .= "\r\n";
    $out .= $post . "\r\n";
    // echo($out);
    fwrite($fp, $out);

    // 注释掉如下代码实现不等待 HTTP 响应,从而实现“异步”
//    $receive = '';
//    while (!feof($fp)) {
//        $receive .= fgets($fp, 128);
//    }
//    echo "<br />" . $receive;


    fclose($fp);
}

这段代码可以如期完成异步 HTTP 效果,但是如果提交的服务端有 NGINX 做 CGI 反代的话,可能会导致上游后端 PHP 接收不到该请求。

NGINX 499

查看 NGINX access log,发现这样的请求会以 499(Client Closed Request)记录。确定问题是因为:客户端主动端口请求连接时,NGINX 不会将该请求代理给上游服务(FastCGI PHP 进程),这个时候 access log 中会以 499 记录这个请求。

要解决这个问题需要将 NGINX FastCGI 忽略客户端中断配置打开:

fastcgi_ignore_client_abort on;

这样无论客户端是否断开,都会将这个请求代理给上游,并且会记录上游服务处理后的返回状态。

另外,还有一个类似配置 proxy_ignore_client_abort on;,这个配置是针对其他类型的反代,PHP 的场景并不适用。

Go 编译跨平台

适用于 [Linux] ,拷贝代码后新建文件 cross.bash,并在 ${go 安装路径}/src 目录下执行。

#!/usr/bin/env bash

export CGO_ENABLED=0

export GOOS=darwin
export GOARCH=386
./make.bash

export GOOS=linux
export GOARCH=386
./make.bash

export GOOS=windows
export GOARCH=386
./make.bash


export GOOS=darwin
export GOARCH=amd64
./make.bash

export GOOS=linux
export GOARCH=amd64
./make.bash

export GOOS=windows
export GOARCH=amd64
./make.bash

一个iOS开发者对tvOS SDK的初探

在Walter Isaacson编写的《Steve Jobs》的最后一章中,Steve说过“我最终实现并让它拥有了你们能想象到的最简单的用户界面”。当时他指的就是Apple TV。

Steve不幸离世已经过去很久了,但是人们一直翘首以盼着这款产品。就在昨天2015年9月9日,超过四个春秋的期盼,我们终于等来了这个礼物,虽然可能与Steve对这款产品的愿景和理想有所差距,但是革命的步伐已经坚实的迈出了第一步。

作为一名iOS开发者,昨天的产品发布会让我心潮澎湃,因为Apple宣布,新的Apple TV集成了App Store,这就意味着我们可以为它开发专有的应用,并且会让我们重新认知已了解的iOS知识,以及会开启更多新的展现想法、创意的机会。

我和其他教程团队的成员已经开始深入研究tvOS SDK,并且正在努力准备一些有价值的tvOS教程(通宵达旦!),在此同时,我想从一个iOS开发者的视角与大家分享我对tvOS的初步印象。

让我们一探究竟吧!

ConurrentHashMap和Hashtable的区别

集合类是Java API的核心,但是我觉得要用好它们是一种艺术。我总结了一些个人的经验,譬如使用ArrayList能够提高性能,而不再需要过时的Vector了,等等。JDK 1.5引入了一些好用的并发集合类,它们对于大型的、要求低延迟的电子商务系统来说非常的有用。这篇文章中将会看看ConcurrentHashMap和Hashtable之间的区别。

这篇文章是HashMap的工作原理以及HashMap和Hashtable的区别的后续。如果你已经读过的话,那么我相信你读完本篇之后会有所收获。