Don't allow svg files containing scripts

merge-requests/30/head
Bob Mottram 2021-09-13 18:51:33 +01:00
parent cadb306b66
commit 192eeaff27
3 changed files with 67 additions and 9 deletions

View File

@ -11,6 +11,7 @@ import os
import email.parser
import urllib.parse
from shutil import copyfile
from utils import dangerousSVG
from utils import removeDomainPort
from utils import isValidLanguage
from utils import getImageExtensions
@ -1017,6 +1018,13 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
except BaseException:
pass
# don't allow scripts within svg files
if detectedExtension == 'svg':
svgStr = mediaBytes[startPos:]
svgStr = svgStr.decode()
if dangerousSVG(svgStr, False):
return None, None
with open(filename, 'wb') as fp:
fp.write(mediaBytes[startPos:])

View File

@ -70,6 +70,7 @@ from utils import getStatusNumber
from utils import getFollowersOfPerson
from utils import removeHtml
from utils import dangerousMarkup
from utils import dangerousSVG
from utils import acctDir
from pgp import extractPGPPublicKey
from pgp import pgpPublicKeyUpload
@ -3412,6 +3413,35 @@ def _testDangerousCSS():
break
def _testDangerousSVG() -> None:
print('testDangerousSVG')
svgContent = \
' <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">' + \
' <circle cx="5" cy="5" r="4" />' + \
'</svg>'
assert not dangerousSVG(svgContent, False)
svgContent = \
' <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">' + \
' <script>' + \
' // <![CDATA[' + \
" window.addEventListener('DOMContentLoaded', () => {" + \
' function attackScript () {' + \
' return `#${OWO}`' + \
' }' + \
'' + \
" document.querySelector('circle')." + \
"addEventListener('click', (e) => {" + \
' e.target.style.fill = attackScript()' + \
' })' + \
' })' + \
' // ]]>' + \
' </script>' + \
'' + \
' <circle cx="5" cy="5" r="4" />' + \
'</svg>'
assert dangerousSVG(svgContent, False)
def _testDangerousMarkup():
print('testDangerousMarkup')
allowLocalNetworkAccess = False
@ -5516,6 +5546,7 @@ def runAllTests():
_translateOntology()
_testGetPriceFromString()
_testFunctions()
_testDangerousSVG()
_testCanReplyTo()
_testDateConversions()
_testAuthorizeSharedItems()

View File

@ -821,16 +821,10 @@ def isLocalNetworkAddress(ipAddress: str) -> bool:
return False
def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool:
"""Returns true if the given content contains dangerous html markup
def _isDangerousString(content: str, allowLocalNetworkAccess: bool,
separators: [], invalidStrings: []) -> bool:
"""Returns true if the given string is dangerous
"""
separators = (['<', '>'], ['&lt;', '&gt;'])
invalidStrings = (
'script', 'noscript',
'canvas', 'style', 'abbr',
'frame', 'iframe', 'html', 'body',
'hr', 'allow-popups', 'allow-scripts'
)
for separatorStyle in separators:
startChar = separatorStyle[0]
endChar = separatorStyle[1]
@ -860,6 +854,31 @@ def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool:
return False
def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool:
"""Returns true if the given content contains dangerous html markup
"""
separators = [['<', '>'], ['&lt;', '&gt;']]
invalidStrings = [
'script', 'noscript',
'canvas', 'style', 'abbr',
'frame', 'iframe', 'html', 'body',
'hr', 'allow-popups', 'allow-scripts'
]
return _isDangerousString(content, allowLocalNetworkAccess,
separators, invalidStrings)
def dangerousSVG(content: str, allowLocalNetworkAccess: bool) -> bool:
"""Returns true if the given svg file content contains dangerous scripts
"""
separators = [['<', '>'], ['&lt;', '&gt;']]
invalidStrings = [
'script'
]
return _isDangerousString(content, allowLocalNetworkAccess,
separators, invalidStrings)
def getDisplayName(baseDir: str, actor: str, personCache: {}) -> str:
"""Returns the display name for the given actor
"""