SSL(Secure Socket Layer) - 데이터 암호와 인증에 대한 프로토콜, 주로 클라이언트 통신 간에 사용
- SSL/TLS 인증은 데이터를 제공할 때 암호화하거나 인증을 한다.
- SSL 인증 시 데이터는 X.509 포맷을 따르며 이때 공개 키는 서버에 저장된다.
- SSL인증은 인증 기관(CA)에 의해 서명된 것을 사용.
- 클라이언트가 서버에 요청할 때, 서버는 인증서를 반환해 준다.
https 제공을 위한 code
package main
import (
"net/http"
)
func main() {
server := http.Server {
Addr: "127.0.0.1:8080",
Handler: nil,
}
server.ListenAndServeTLS("cert.pem", "key.pem")
}
http 전송을 할 때에는 .ListnAndServer() method를 사용하지만 https 전송을 위해서는 SSL 인증서인 cert.pem 파일과 서버를 위한 개인 키인 key.pem 파일이 필요하다.
개인키 생성하기
- crypto/x509 라이브러리를 이용해서 인증서를 생성
- 인증서 생성을 위해 개인 키가 요청되면 개인 키를 이용해 인증서를 만들고 파일로 저장
이 때 인증서의 시리얼번호가 필요한데, 이 값은 실제로는 유일한 번호로 인증기관 CA에 의해 발행되는 것
현재는 테스트이기 때문에 랜덤한 매우 큰 정수를 생성하고, subject를 설정해준다.
max := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, max)
subject := pkix.Name{
Organization: [] string {"test Organization"},
OrganizationalUnit: [] string {"test"},
CommonName: "Go Web Programming",
}
인증서의 구조
template := x509.Certificate{
SerialNumber:serialNumber,
Subject:subject,
NotBefore:time.Now(),
NotAfter:time.Now().Add(365 * 24 * time.Hour),
KeyUsage:x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage:[] x509.ExtKeyUsage {x509.ExtKeyUsageServerAuth},
IPAddresses:[] net.IP {net.ParseIP("127.0.0.1")},
}
발급 유효 기간을 현재부터 1년뒤로 설정해준다. (NotBefore, NotAfter)
KeyUsage, ExtKeyUsage 필드는 X.509 인증서를 가리키며 서버 인증을 위해 사용 된다.
또한 로컬에서만 동작하도록 127.0.0.1에서만 동작하는 인증서를 설정
구조를 만들었으면, crypto/rsa 라이브러리를 이용하여 RSA 개인 키를 생성
pk, _ := rsa.GenerateKey(rand.Reader, 2048)
encoding/pem 라이브러리를 이용하여 인증서를 cert.pem 파일로 인코딩
derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk)
certOut, _ := os.Create("cert.pem")
pem.Encode(certOut, &pem.Block{Type:"CERTIFICATE", Bytes:derBytes})
certOut.Close()
key.pem 파일을 만들고, 우리가 생성했던 키를 저장한다.
keyOut, _ := os.Create("key.pem")
pem.Encode(keyOut, &pem.Block{Type:"RSA PRIVATE KEY", Bytes:x509.MarshalPKCS1PrivateKey(pk)})
keyOut.Close()
전체 코드를 실행하면
다음과 같이 cert.pem, key.pem 파일이 생성된 것을 확인할 수 있다.
key 생성 전체 코드
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"os"
"time"
)
func main() {
max := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, max)
subject := pkix.Name{
Organization: [] string {"test Organization"},
OrganizationalUnit: [] string {"test"},
CommonName: "Go Web Programming",
}
template := x509.Certificate{
SerialNumber:serialNumber,
Subject:subject,
NotBefore:time.Now(),
NotAfter:time.Now().Add(365 * 24 * time.Hour),
KeyUsage:x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage:[] x509.ExtKeyUsage {x509.ExtKeyUsageServerAuth},
IPAddresses:[] net.IP {net.ParseIP("127.0.0.1")},
}
pk, _ := rsa.GenerateKey(rand.Reader, 2048)
derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk)
certOut, _ := os.Create("cert.pem")
pem.Encode(certOut, &pem.Block{Type:"CERTIFICATE", Bytes:derBytes})
certOut.Close()
keyOut, _ := os.Create("key.pem")
pem.Encode(keyOut, &pem.Block{Type:"RSA PRIVATE KEY", Bytes:x509.MarshalPKCS1PrivateKey(pk)})
keyOut.Close()
}
이제 https 전송을 해보자
package main
import (
"fmt"
"net/http"
)
type handler struct {}
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello world!")
}
func main() {
handler := handler{}
server := http.Server {
Addr: "127.0.0.1:8080",
Handler: &handler,
}
server.ListenAndServeTLS("cert.pem", "key.pem")
}
위 코드를 실행해보면,
인증 받지 않을 key이기 때문에 위험표시가 나오고, [고급] - [연결]을 해주면 접속할 수 있다.
테스트용 https 전송이 된것을 확인할 수 있다.
'Language > Go' 카테고리의 다른 글
[Go] - web programming : 액션 (0) | 2020.01.16 |
---|---|
[Go] - web programming : 템플릿과 템플릿 엔진 (0) | 2020.01.15 |
[Go] - web programming : 쿠키 cookie (0) | 2020.01.06 |
[Go] - web programming : request 처리 및 response 작성 (1) | 2020.01.04 |
[Go] - web programming : handler 기초 (0) | 2020.01.03 |