前面我们一直在讲关于Go语言的一些基础的包中的函数,那么我们写好程序的同时,也需要考虑到程序的一个安全问题才是最重要的,安全编程和测试一直是开发过程中不可或缺的一部分。
现如今的信息数据化和传输网络化对数据和数据传输的安全提出了很大的要求,在这两个环节上,需要对数据进行加密,并使用安全的数据传输体系。
安全相关的基础概念
数据加密
单秘钥的加密方法被称为对称加密,在加密和解密的过程中,使用的秘钥只有一个,常见的对称加密算法有DES
,AES
,RC4
。
而双秘钥的加密方法则被称为非对称加密。在加密和解密的过程中,使用的秘钥有两个,私钥和公钥都可以被用作加密或者解密,但是用私钥加密的明文,必须要用对应的公钥解密。常见的非对称加密算法有RSA
等。
前面所说的这两大类内容,有一个共同的特点,那就是数据可以加密,同时也可以解密,但事实上,还有一种加密需求是只需要加密,这个时候,可以考虑使用哈希算法。
哈希算法是一种从任意数据中创建固定长度摘要信息的办法。常见的哈希算法包括MD5
,SHA-256
等。
数字签名
数字签名,是指用于标记数字文件拥有者,创造者,分发者身份的字符串,数字签名拥有标记文件身份,分发的不可抵赖性等作用。目前,常用的数字签名采用了非对称加密的方式。
PKI体系
PKI,全称公钥基础设施,是使用非对称加密理论,提供数字签名,加密,数字证书等服务的体系,一般包括权威认证机构(CA),数字证书库,秘钥备份及恢复系统,证书作废系统和应用编程借口(API)等。
通信安全
哈希函数
package main
import (
"crypto/md5"
"crypto/sha256"
"fmt"
)
func main() {
TestString := "Hello, golang!"
Md5Inst := md5.New()
Md5Inst.Write([]byte(TestString))
Result := Md5Inst.Sum([]byte(""))
fmt.Printf("%x", Result)
fmt.Println()
Sha256 := sha256.New()
Sha256.Write([]byte(TestString))
Result = Sha256.Sum([]byte(""))
fmt.Printf("%x", Result)
}
/** The result is:
4b03b629e0efd2f8a84a74571b115015
a987c91c6c223b11b91c71d114fc1402603dfee532a34954cf0cd178a0683781
*/
同样,我们还可以对文件内容进行加密计算:
package main
import (
"crypto/md5"
"crypto/sha256"
"fmt"
"io"
"log"
"os"
)
func main() {
fileName := "goProgramming/security/14-1.go"
infile, err :=os.Open(fileName)
if err == nil {
md5h := md5.New()
io.Copy(md5h, infile)
fmt.Printf("The md5 of file is: %x", md5h.Sum([]byte("")))
fmt.Println()
sha256h := sha256.New()
io.Copy(sha256h, infile)
fmt.Printf("The sha256 of file is: %x", sha256h.Sum([]byte("")))
} else {
log.Fatal(err)
os.Exit(1)
}
}
加密通信流程
一般的HTTPS
基于SSL
协议。通过SSL
可以把HTTP
包数据以非对称加密的形式往返于浏览器和站点之间,从而避免被第三方非法获取。而TSL
是建立于SSL V2.0
之上的兼容协议,他们主要的区别在于所支持的加密算法。
我们来看一下大致的SSL/TLS
工作方式:
在浏览器中输入
HTTPS
协议的网址;
服务器向浏览器返回证书;
浏览器检查该证书的合法性;
浏览器使用证书中的公钥加密一个随机对称密钥,并将加密后的密钥和使用密钥加密后的请求URL
一起发送到服务器;
服务器用私钥解密随机对称密钥,并用获取的密钥解密加密的请求URL
;
服务器把用户请求的网页用密钥加密,并返回给用户;
用户浏览器用密钥解密服务器发来的网页数据,并将其显示出来;
支持HTTPS的Web服务器
Go语言目前实现了TLS
协议的部分功能,已经可以提供最基础的安全层服务。我们一起来看一下如何实现支持TSL
的Web
服务器:
const SERVER_PORT = 8000
const SERVER_DOMAIN = "localhost"
const RESPONSE_TEMPLATE = "Hello World."
func rootHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
w.Header().Set("COntent-Length",fmt.Sprint(len(RESPONSE_TEMPLATE)))
w.Write([]byte(RESPONSE_TEMPLATE))
}
func main() {
http.HandleFunc(fmt.Sprintf("%s:%d/", SERVER_DOMAIN, SERVER_PORT), rootHandler)
http.ListenAndServeTLS(fmt.Sprintf(":%d", SERVER_PORT), "some.crt", "some.key", nil)
}
我们在这里使用的是http.ListenAndServerTLS()
这个方法,如果我们使用非TLS
方法,只需要替换成http.ListenAndServer(fmt.Sprintf(":%d", SERVER_PORT), nil)
即可。
支持HTTPS的文件服务器
利用Go语言标准库中提供的完备封装,也可以很容易地实现一个支持HTTPS
的文件服务器。
h := http.FileServer(http.Dir("."))
http.ListenAndServerTLS(":8001", "rui.crt", "rui.key", h)
这是一个极其简单的例子,只是单纯的介绍了FileServer
函数的存在,这个函数的参数只有一个那么久是根目录路径,其他任务全部由ListenAndServer*
等函数完成。