Skip to content

Commit 2a003a6

Browse files
author
jojoliang
committed
默认不跟随,检验URL
1 parent bcc8fc4 commit 2a003a6

File tree

2 files changed

+169
-5
lines changed

2 files changed

+169
-5
lines changed

cos.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"encoding/base64"
77
"encoding/xml"
8+
"errors"
89
"fmt"
910
"io"
1011
"io/ioutil"
@@ -25,7 +26,7 @@ import (
2526

2627
const (
2728
// Version current go sdk version
28-
Version = "0.7.55"
29+
Version = "0.7.56"
2930
UserAgent = "cos-go-sdk-v5/" + Version
3031
contentTypeXML = "application/xml"
3132
defaultServiceBaseURL = "http://service.cos.myqcloud.com"
@@ -43,8 +44,15 @@ var (
4344
hostSuffix = regexp.MustCompile(`^.*((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`)
4445
hostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+-[0-9]+\.){0,1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`)
4546
metaInsightHostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([0-9]+\.){1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`)
46-
bucketChecker = regexp.MustCompile(`^[a-z0-9-]+-[0-9]+$`)
47-
invalidBucketErr = fmt.Errorf("invalid bucket format, please check your cos.BaseURL")
47+
bucketChecker = regexp.MustCompile(`^[a-z0-9-]+-[0-9]+$`)
48+
regionChecker = regexp.MustCompile(`^[a-z-1]+$`)
49+
50+
// 校验传入的url
51+
domainSuffix = regexp.MustCompile(`^.*\.(myqcloud\.com(:[0-9]+){0,1}|tencentcos\.cn(:[0-9]+){0,1})$`)
52+
bucketDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+-[0-9]+\.){0,1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn)(:[0-9]+){0,1}$`)
53+
serviceDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}((service.cos.myqcloud.com|service.cos-internal.tencentcos.cn|service.cos.tencentcos.cn)|(cos|cos-internal)\.[a-z-1]+\.(myqcloud\.com|tencentcos\.cn))(:[0-9]+){0,1}$`)
54+
batchDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}([0-9]+\.){1}cos-control\.[a-z-1]+\.(myqcloud\.com|tencentcos\.cn)(:[0-9]+){0,1}$`)
55+
invalidBucketErr = fmt.Errorf("invalid bucket format, please check your cos.BaseURL")
4856

4957
switchHost = regexp.MustCompile(`([a-z0-9-]+-[0-9]+\.)(cos\.[a-z-1]+)\.(myqcloud\.com)(:[0-9]+){0,1}$`)
5058
accelerateDomainSuffix = "accelerate.myqcloud.com"
@@ -70,6 +78,27 @@ type BaseURL struct {
7078
MetaInsightURL *url.URL
7179
}
7280

81+
func (*BaseURL) innerCheck(u *url.URL, reg *regexp.Regexp) bool {
82+
if u == nil {
83+
return true
84+
}
85+
urlStr := strings.TrimRight(u.String(), "/")
86+
if !strings.HasPrefix(urlStr, "https://") && !strings.HasPrefix(urlStr, "http://") {
87+
return false
88+
}
89+
if strings.Count(urlStr, "/") > 2 {
90+
return false
91+
}
92+
if domainSuffix.MatchString(urlStr) && !reg.MatchString(urlStr) {
93+
return false
94+
}
95+
return true
96+
}
97+
98+
func (u *BaseURL) Check() bool {
99+
return u.innerCheck(u.BucketURL, bucketDomainChecker) && u.innerCheck(u.ServiceURL, serviceDomainChecker) && u.innerCheck(u.BatchURL, batchDomainChecker)
100+
}
101+
73102
// NewBucketURL 生成 BaseURL 所需的 BucketURL
74103
//
75104
// bucketName: bucket名称, bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
@@ -81,7 +110,7 @@ func NewBucketURL(bucketName, region string, secure bool) (*url.URL, error) {
81110
schema = "http"
82111
}
83112

84-
if region == "" {
113+
if region == "" || !regionChecker.MatchString(region) {
85114
return nil, fmt.Errorf("region[%v] is invalid", region)
86115
}
87116
if bucketName == "" || !strings.ContainsAny(bucketName, "-") {
@@ -130,17 +159,33 @@ type Client struct {
130159
MetaInsight *MetaInsightService
131160

132161
Conf *Config
162+
163+
invalidURL bool
133164
}
134165

135166
type service struct {
136167
client *Client
137168
}
138169

170+
// go http default CheckRedirect
171+
func HttpDefaultCheckRedirect(req *http.Request, via []*http.Request) error {
172+
if len(via) >= 10 {
173+
return errors.New("stopped after 10 redirects")
174+
}
175+
return nil
176+
}
177+
139178
// NewClient returns a new COS API client.
140179
func NewClient(uri *BaseURL, httpClient *http.Client) *Client {
141180
if httpClient == nil {
142181
httpClient = &http.Client{}
143182
}
183+
// avoid SSRF, default don't follow 3xx
184+
if httpClient.CheckRedirect == nil {
185+
httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
186+
return http.ErrUseLastResponse
187+
}
188+
}
144189

145190
baseURL := &BaseURL{}
146191
if uri != nil {
@@ -154,6 +199,10 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client {
154199
if baseURL.ServiceURL == nil {
155200
baseURL.ServiceURL, _ = url.Parse(defaultServiceBaseURL)
156201
}
202+
var invalidURL bool
203+
if !baseURL.Check() {
204+
invalidURL = true
205+
}
157206

158207
c := &Client{
159208
client: httpClient,
@@ -169,6 +218,7 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client {
169218
},
170219
ObjectKeySimplifyCheck: true,
171220
},
221+
invalidURL: invalidURL,
172222
}
173223
c.common.client = c
174224
c.Service = (*ServiceService)(&c.common)
@@ -219,6 +269,9 @@ func (c *Client) GetCredential() *Credential {
219269
}
220270

221271
func (c *Client) newRequest(ctx context.Context, baseURL *url.URL, uri, method string, body interface{}, optQuery interface{}, optHeader interface{}, isRetry bool) (req *http.Request, err error) {
272+
if c.invalidURL {
273+
return nil, invalidBucketErr
274+
}
222275
if !checkURL(baseURL) {
223276
host := baseURL.String()
224277
if c.BaseURL.MetaInsightURL != baseURL || !metaInsightHostPrefix.MatchString(host) {
@@ -292,7 +345,7 @@ func (c *Client) doAPI(ctx context.Context, req *http.Request, result interface{
292345
ctx, cancel = context.WithCancel(ctx)
293346
defer cancel()
294347
}
295-
req = req.WithContext(ctx)
348+
//req = req.WithContext(ctx)
296349

297350
resp, err := c.client.Do(req)
298351
if err != nil {

cos_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,114 @@ func Test_CheckRetrieable(t *testing.T) {
244244
t.Errorf("CheckRetrieable failed, switch: %v, retry: %v", res.String(), retry)
245245
}
246246
}
247+
248+
func Test_BaseURL(t *testing.T) {
249+
u, _ := url.Parse("https://example-125000000.cos.ap-chengdu.myqcloud.com")
250+
if !(&BaseURL{BucketURL: u}).Check() {
251+
t.Errorf("BaseURL check failed: %v", u)
252+
}
253+
u, _ = url.Parse("https://example-125000000.cos-website.ap-chengdu.myqcloud.com")
254+
if !(&BaseURL{BucketURL: u}).Check() {
255+
t.Errorf("BaseURL check failed: %v", u)
256+
}
257+
u, _ = url.Parse("https://example-125000000.cos-internal.ap-chengdu.tencentcos.cn")
258+
if !(&BaseURL{BucketURL: u}).Check() {
259+
t.Errorf("BaseURL check failed: %v", u)
260+
}
261+
u, _ = url.Parse("https://example-125000000.cos.ap-chengdu.tencentcos.cn")
262+
if !(&BaseURL{BucketURL: u}).Check() {
263+
t.Errorf("BaseURL check failed: %v", u)
264+
}
265+
u, _ = url.Parse("https://example-125000000.cos.accelerate.myqcloud.com")
266+
if !(&BaseURL{BucketURL: u}).Check() {
267+
t.Errorf("BaseURL check failed: %v", u)
268+
}
269+
u, _ = url.Parse("https://example-125000000.cos-internal.accelerate.tencentcos.cn")
270+
if !(&BaseURL{BucketURL: u}).Check() {
271+
t.Errorf("BaseURL check failed: %v", u)
272+
}
273+
u, _ = url.Parse("http://example-125000000.cos.ap-chengdu.myqcloud.com:8080")
274+
if !(&BaseURL{BucketURL: u}).Check() {
275+
t.Errorf("BaseURL check failed: %v", u)
276+
}
277+
u, _ = url.Parse("http://example-125000000.cos-internal.ap-chengdu.tencentcos.cn:80")
278+
if !(&BaseURL{BucketURL: u}).Check() {
279+
t.Errorf("BaseURL check failed: %v", u)
280+
}
281+
u, _ = url.Parse("https://example-125000000.cos-internal.accelerate.tencentcos.cn:443")
282+
if !(&BaseURL{BucketURL: u}).Check() {
283+
t.Errorf("BaseURL check failed: %v", u)
284+
}
285+
286+
u, _ = url.Parse("https://[email protected]/.myqcloud.com")
287+
if (&BaseURL{BucketURL: u}).Check() {
288+
t.Errorf("BaseURL check failed: %v", u)
289+
}
290+
u, _ = url.Parse("https://[email protected]/.myqcloud.com:443")
291+
if (&BaseURL{BucketURL: u}).Check() {
292+
t.Errorf("BaseURL check failed: %v", u)
293+
}
294+
u, _ = url.Parse("https://[email protected]/myqcloud.com")
295+
if (&BaseURL{BucketURL: u}).Check() {
296+
t.Errorf("BaseURL check failed: %v", u)
297+
}
298+
299+
u, _ = url.Parse("https://service.cos.myqcloud.com")
300+
if !(&BaseURL{ServiceURL: u}).Check() {
301+
t.Errorf("BaseURL check failed: %v", u)
302+
}
303+
u, _ = url.Parse("http://service.cos-internal.tencentcos.cn")
304+
if !(&BaseURL{ServiceURL: u}).Check() {
305+
t.Errorf("BaseURL check failed: %v", u)
306+
}
307+
u, _ = url.Parse("http://service.cos.tencentcos.cn:80")
308+
if !(&BaseURL{ServiceURL: u}).Check() {
309+
t.Errorf("BaseURL check failed: %v", u)
310+
}
311+
u, _ = url.Parse("http://cos.ap-guangzhou.myqcloud.com")
312+
if !(&BaseURL{ServiceURL: u}).Check() {
313+
t.Errorf("BaseURL check failed: %v", u)
314+
}
315+
u, _ = url.Parse("http://cos.ap-guangzhou.myqcloud.com")
316+
if !(&BaseURL{ServiceURL: u}).Check() {
317+
t.Errorf("BaseURL check failed: %v", u)
318+
}
319+
u, _ = url.Parse("http://cos.ap-guangzhou.tencentcos.cn:8080")
320+
if !(&BaseURL{ServiceURL: u}).Check() {
321+
t.Errorf("BaseURL check failed: %v", u)
322+
}
323+
u, _ = url.Parse("http://[email protected]/.myqcloud.com")
324+
if (&BaseURL{ServiceURL: u}).Check() {
325+
t.Errorf("BaseURL check failed: %v", u)
326+
}
327+
u, _ = url.Parse("http://[email protected]/.myqcloud.com")
328+
if (&BaseURL{ServiceURL: u}).Check() {
329+
t.Errorf("BaseURL check failed: %v", u)
330+
}
331+
332+
u, _ = url.Parse("http://123.cos-control.ap-guangzhou.myqcloud.com")
333+
if !(&BaseURL{BatchURL: u}).Check() {
334+
t.Errorf("BaseURL check failed: %v", u)
335+
}
336+
u, _ = url.Parse("http://123.cos-control.ap-guangzhou.tencentcos.cn")
337+
if !(&BaseURL{BatchURL: u}).Check() {
338+
t.Errorf("BaseURL check failed: %v", u)
339+
}
340+
u, _ = url.Parse("http://123.cos-control.ap-guangzhou.myqcloud.com:8080")
341+
if !(&BaseURL{BatchURL: u}).Check() {
342+
t.Errorf("BaseURL check failed: %v", u)
343+
}
344+
u, _ = url.Parse("http://cos-control.ap-guangzhou.tencentcos.cn")
345+
if (&BaseURL{BatchURL: u}).Check() {
346+
t.Errorf("BaseURL check failed: %v", u)
347+
}
348+
u, _ = url.Parse("http://cos-control.ap-guangzhou.myqcloud.com")
349+
if (&BaseURL{BatchURL: u}).Check() {
350+
t.Errorf("BaseURL check failed: %v", u)
351+
}
352+
u, _ = url.Parse("http://cos-control.ap-guangzhou.myqcloud.com/www.com")
353+
if (&BaseURL{BatchURL: u}).Check() {
354+
t.Errorf("BaseURL check failed: %v", u)
355+
}
356+
357+
}

0 commit comments

Comments
 (0)