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 email.parser
import urllib.parse import urllib.parse
from shutil import copyfile from shutil import copyfile
from utils import dangerousSVG
from utils import removeDomainPort from utils import removeDomainPort
from utils import isValidLanguage from utils import isValidLanguage
from utils import getImageExtensions from utils import getImageExtensions
@ -1017,6 +1018,13 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
except BaseException: except BaseException:
pass 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: with open(filename, 'wb') as fp:
fp.write(mediaBytes[startPos:]) fp.write(mediaBytes[startPos:])

View File

@ -70,6 +70,7 @@ from utils import getStatusNumber
from utils import getFollowersOfPerson from utils import getFollowersOfPerson
from utils import removeHtml from utils import removeHtml
from utils import dangerousMarkup from utils import dangerousMarkup
from utils import dangerousSVG
from utils import acctDir from utils import acctDir
from pgp import extractPGPPublicKey from pgp import extractPGPPublicKey
from pgp import pgpPublicKeyUpload from pgp import pgpPublicKeyUpload
@ -3412,6 +3413,35 @@ def _testDangerousCSS():
break 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(): def _testDangerousMarkup():
print('testDangerousMarkup') print('testDangerousMarkup')
allowLocalNetworkAccess = False allowLocalNetworkAccess = False
@ -5516,6 +5546,7 @@ def runAllTests():
_translateOntology() _translateOntology()
_testGetPriceFromString() _testGetPriceFromString()
_testFunctions() _testFunctions()
_testDangerousSVG()
_testCanReplyTo() _testCanReplyTo()
_testDateConversions() _testDateConversions()
_testAuthorizeSharedItems() _testAuthorizeSharedItems()

View File

@ -821,16 +821,10 @@ def isLocalNetworkAddress(ipAddress: str) -> bool:
return False return False
def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool: def _isDangerousString(content: str, allowLocalNetworkAccess: bool,
"""Returns true if the given content contains dangerous html markup 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: for separatorStyle in separators:
startChar = separatorStyle[0] startChar = separatorStyle[0]
endChar = separatorStyle[1] endChar = separatorStyle[1]
@ -860,6 +854,31 @@ def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool:
return False 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: def getDisplayName(baseDir: str, actor: str, personCache: {}) -> str:
"""Returns the display name for the given actor """Returns the display name for the given actor
""" """