-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecurity.go
141 lines (127 loc) · 3.47 KB
/
security.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package main
import (
"bytes"
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"net"
"sync"
)
const (
CheckSecuriry_Off int = iota
CheckSecuriry_Queue
CheckSecuriry_Aggressive
CheckSecuriry_LogOnly
)
const (
SecurityStatus_Unknown int = iota
SecurityStatus_InProgress
SecurityStatus_WrongCert
SecurityStatus_HTTPS
)
type SecurityResults struct {
sync.RWMutex
r map[string]int
}
type Security struct {
Title string
RedirUrl string
Policy int
EnforceHTTPSHostnames bool
EnforceHTTPSVerifiedCerts bool
CheckProxyTunnels bool
AllowUnknownProtocol bool
Results SecurityResults
}
func (s *Security) Redirect(id string, out chan string, input *Input, reason string) bool {
redir_url, log_line := FormatRedirect(s.Title, s.RedirUrl, input, reason)
if s.Policy == CheckSecuriry_LogOnly {
ChangeLogger.Printf(log_line + " (DRY-RUN)")
return false
} else {
out <- id + " OK rewrite-url=" + redir_url
ChangeLogger.Printf(log_line)
return true
}
}
func (s *Security) CheckHTTPSHostnameIsIP(url URL) bool {
ip := net.ParseIP(url.Host)
return ip != nil
}
func (s *Security) CheckHTTPSWrongCert(url URL) bool {
s.Results.RLock()
check_res, ok := s.Results.r[url.Host+url.Port]
s.Results.RUnlock()
if !ok || check_res == SecurityStatus_Unknown {
if s.Policy == CheckSecuriry_Aggressive {
s.CheckHTTPSRoot(url)
s.Results.RLock()
check_res, _ = s.Results.r[url.Host+url.Port]
s.Results.RUnlock()
} else {
go s.CheckHTTPSRoot(url)
return false
}
}
return check_res == SecurityStatus_WrongCert
}
func (s *Security) CheckHTTPSRoot(url URL) {
ErrorLogger.Printf("Checking %s:%s\n", url.Host, url.Port)
s.Results.Lock()
s.Results.r[url.Host+url.Port] = SecurityStatus_InProgress
s.Results.Unlock()
tlscfg := tls.Config{InsecureSkipVerify: true, MinVersion: tls.VersionSSL30}
tlscfg.ServerName = url.Host
conn, err_conn := tls.Dial("tcp", fmt.Sprintf("%s:%s", url.Host, url.Port), &tlscfg)
if err_conn != nil {
ErrorLogger.Printf("Failed to dial %s:%s - %s\n", url.Host, url.Port, err_conn)
s.Results.Lock()
s.Results.r[url.Host+url.Port] = SecurityStatus_Unknown
s.Results.Unlock()
return
}
state := conn.ConnectionState()
opts := x509.VerifyOptions{
DNSName: tlscfg.ServerName,
Intermediates: x509.NewCertPool(),
}
for i, cert := range state.PeerCertificates {
if i == 0 {
continue
}
opts.Intermediates.AddCert(cert)
}
_, err_verify := state.PeerCertificates[0].Verify(opts)
if err_verify != nil {
s.Results.Lock()
s.Results.r[url.Host+url.Port] = SecurityStatus_WrongCert
s.Results.Unlock()
ErrorLogger.Printf("%s:%s - %s\n", url.Host, url.Port, err_verify)
return
}
message := fmt.Sprintf("GET / HTTP/1.1\nHost: %s\n\n", tlscfg.ServerName)
_, err_write := io.WriteString(conn, message)
if err_write != nil {
ErrorLogger.Printf("Failed to write '%s' to '%s:%s' - %s", message, url.Host, url.Port, err_write)
s.Results.Lock()
s.Results.r[url.Host+url.Port] = SecurityStatus_Unknown
s.Results.Unlock()
return
}
reply := make([]byte, 256)
_, err_read := conn.Read(reply)
if err_read != nil {
ErrorLogger.Printf("Failed to read from '%s:%s' - %s", url.Host, url.Port, err_read)
s.Results.Lock()
s.Results.r[url.Host+url.Port] = SecurityStatus_Unknown
s.Results.Unlock()
return
}
if bytes.HasPrefix(reply, []byte("HTTP/")) {
s.Results.Lock()
s.Results.r[url.Host+url.Port] = SecurityStatus_HTTPS
s.Results.Unlock()
return
}
}