1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-01-23 11:14:48 +02:00

Sanitize SVG

This commit is contained in:
DarthSim 2022-06-10 18:07:09 +06:00
parent 8f91fa5bd4
commit e1e2277a32
7 changed files with 89 additions and 1 deletions

View File

@ -79,6 +79,8 @@ var (
AllowedSources []*regexp.Regexp
SanitizeSvg bool
CookiePassthrough bool
CookieBaseURL string
@ -237,6 +239,8 @@ func Reset() {
AllowedSources = make([]*regexp.Regexp, 0)
SanitizeSvg = true
CookiePassthrough = false
CookieBaseURL = ""
@ -344,6 +348,8 @@ func Configure() error {
configurators.Patterns(&AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
configurators.Bool(&SanitizeSvg, "IMGPROXY_SANITIZE_SVG")
configurators.Bool(&JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE")
configurators.Bool(&PngInterlaced, "IMGPROXY_PNG_INTERLACED")
configurators.Bool(&PngQuantize, "IMGPROXY_PNG_QUANTIZE")

View File

@ -91,6 +91,8 @@ You can limit allowed source URLs with the following variable:
* Good: `http://example.com/`
If the trailing slash is absent, `http://example.com@baddomain.com` would be a permissable URL, however, the request would be made to `baddomain.com`.
* `IMGPROXY_SANITIZE_SVG`: when true, imgproxy will remove scripts from SVG images to prevent XSS attacks. Defaut: `true`
When using imgproxy in a development environment, it can be useful to ignore SSL verification:
* `IMGPROXY_IGNORE_SSL_VERIFICATION`: when true, disables SSL verification, so imgproxy can be used in a development environment with self-signed SSL certificates.

1
go.mod
View File

@ -23,6 +23,7 @@ require (
github.com/prometheus/client_golang v1.12.1
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.1
github.com/tdewolff/parse/v2 v2.6.0 // indirect
github.com/trimmer-io/go-xmp v1.0.0
go.uber.org/automaxprocs v1.5.1
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9

3
go.sum
View File

@ -1078,6 +1078,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tdewolff/parse/v2 v2.6.0 h1:f2D7w32JtqjCv6SczWkfwK+m15et42qEtDnZXHoNY70=
github.com/tdewolff/parse/v2 v2.6.0/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tidwall/btree v0.3.0/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
github.com/tidwall/buntdb v1.2.0/go.mod h1:XLza/dhlwzO6dc5o/KWor4kfZSt3BP8QV+77ZMKfI58=

View File

@ -22,6 +22,7 @@ import (
"github.com/imgproxy/imgproxy/v3/processing"
"github.com/imgproxy/imgproxy/v3/router"
"github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/svg"
"github.com/imgproxy/imgproxy/v3/vips"
)
@ -275,6 +276,22 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
if originData.Type == po.Format || po.Format == imagetype.Unknown {
// Don't process SVG
if originData.Type == imagetype.SVG {
if config.SanitizeSvg {
sanitized, svgErr := svg.Satitize(originData.Data)
if svgErr != nil {
panic(svgErr)
}
// Since we'll replace origin data, it's better to close it to return
// it's buffer to the pool
originData.Close()
originData = &imagedata.ImageData{
Data: sanitized,
Type: imagetype.SVG,
}
}
respondWithImage(reqID, r, rw, statusCode, originData, po, imageURL, originData)
return
}

View File

@ -20,6 +20,7 @@ import (
"github.com/imgproxy/imgproxy/v3/imagetype"
"github.com/imgproxy/imgproxy/v3/options"
"github.com/imgproxy/imgproxy/v3/router"
"github.com/imgproxy/imgproxy/v3/svg"
"github.com/imgproxy/imgproxy/v3/vips"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
@ -289,7 +290,9 @@ func (s *ProcessingHandlerTestSuite) TestSkipProcessingSVG() {
assert.Equal(s.T(), 200, res.StatusCode)
actual := s.readBody(res)
expected := s.readTestFile("test1.svg")
expected, err := svg.Satitize(s.readTestFile("test1.svg"))
assert.Nil(s.T(), err)
assert.True(s.T(), bytes.Equal(expected, actual))
}

56
svg/svg.go Normal file
View File

@ -0,0 +1,56 @@
package svg
import (
"bytes"
"io"
"strings"
"github.com/tdewolff/parse/v2"
"github.com/tdewolff/parse/v2/xml"
)
func Satitize(data []byte) ([]byte, error) {
r := bytes.NewReader(data)
l := xml.NewLexer(parse.NewInput(r))
buf := new(bytes.Buffer)
buf.Grow(len(data))
ignoreTag := 0
for {
tt, tdata := l.Next()
if ignoreTag > 0 {
switch tt {
case xml.EndTagToken, xml.StartTagCloseVoidToken:
ignoreTag--
case xml.StartTagToken:
ignoreTag++
}
continue
}
switch tt {
case xml.ErrorToken:
if l.Err() != io.EOF {
return nil, l.Err()
}
return buf.Bytes(), nil
case xml.StartTagToken:
if strings.ToLower(string(l.Text())) == "script" {
ignoreTag++
continue
}
buf.Write(tdata)
case xml.AttributeToken:
if strings.ToLower(string(l.Text())) == "onload" {
continue
}
buf.Write(tdata)
default:
buf.Write(tdata)
}
}
}