Example #1
0
class TestCertificates(TestCase):

    BASE_MESSAGE = {
        'id': ('javascript', 'predefinedentities', 'cert_db'),
        'description':
        Matches('Access to the X509 certificate '
                'database'),
        'signing_help':
        Matches('avoid interacting with the '
                'certificate and trust databases'),
        'signing_severity':
        'high'
    }

    @parametrize('interface', ('nsIX509CertDB', 'nsIX509CertDB2',
                               'nsIX509CertList', 'nsICertOverrideService'))
    def test_cert_db_interfaces(self, interface):
        """Test that use of the certificate DB interfaces raises a signing
        warning."""

        self.run_script('Cc[""].getService(Ci.{0});'.format(interface))
        self.assert_warnings(self.BASE_MESSAGE)

    @parametrize('contract', ('@mozilla.org/security/x509certdb;1',
                              '@mozilla.org/security/x509certlist;1',
                              '@mozilla.org/security/certoverride;1'))
    def test_cert_db_contracts(self, contract):
        """Test that access to the certificate DB contract IDs raises a signing
        warning."""

        self.run_script('Cc["{0}"]'.format(contract))
        self.assert_warnings(self.BASE_MESSAGE)
Example #2
0
class TestCTypes(TestCase):

    BASE_MESSAGE = {
        'id': ('testcases_javascript', 'security', 'ctypes'),
        'description':
        Matches('ctypes.*can lead to serious, and often '
                'exploitable, errors'),
        'signing_help':
        Matches('avoid.*native binaries'),
        'signing_severity':
        'high'
    }

    def test_ctypes_usage(self):
        """Test that use of the ctypes global triggers a signing warning."""

        self.run_script('ctypes.open("foo.so")')
        self.assert_warnings(self.BASE_MESSAGE)

    @parametrize('script', (
        'Cu.import("resource://gre/modules/ctypes.jsm?foo");',
        'Components.utils.import("resource:///modules/ctypes.jsm");',
    ))
    def test_ctypes_module(self, script):
        """Test that references to ctypes.jsm trigger a signing warning."""

        self.run_script(script)
        self.assert_warnings(self.BASE_MESSAGE)
Example #3
0
    def test_setTimeout_dynamic(self, setTimeout_pattern):
        """Test that running setTimeout or setInterval with a dynamic,
        non-function value results in the appropriate warning."""

        self.run_script(setTimeout_pattern.format(code='foo'))

        self.assert_warnings(
            dict(
                self.BASE_MESSAGE,
                description=Matches('function expressions as their first arg'),
                signing_help=Matches('do not ever call.*string arguments')))
Example #4
0
    def test_innerhtml_dynamic(self):
        """Test that dynamic values assigned to innerHTML are flagged."""

        self.set_html('foo')

        self.assert_warnings({
            'id': (Exists(), 'set_%s' % self.method, 'variable_assignment'),
            'message':
            Matches('Markup should not.*dynamically'),
            'description':
            Matches('not been adequately sanitized')
        })
Example #5
0
    def test_document_write(self):
        """Test that any use of `document.write` usses a warning that it's
        deprecated."""

        self.set_html('foo')
        self.assert_warnings({
            'id': ('js', 'document.write', 'evil'),
            'message':
            Matches('document\.write.*strongly discouraged'),
            'description':
            Matches('should not be used')
        })
Example #6
0
    def test_function_export(self, method):
        """Test that the use of function export APIs raises signing
        warnings."""

        self.run_script('Components.utils.{0}(thing)'.format(method))

        self.assert_warnings({
            'description':
            Matches('expose privileged functionality'),
            'signing_help':
            Matches('exposing APIs to unprivileged code'),
            'signing_severity':
            'low'
        })
Example #7
0
class TestPrototype(TestCase):
    MESSAGE = {
        'id': ('testcases_javascript', 'performance', 'prototype_mutation'),
        'message': Contains('deprecated'),
        'description': Matches(r'`Object\.create`'),
    }

    def test_set__proto__(self):
        """Test changes to the __proto__ property are flagged."""

        self.run_script('obj.__proto__ = foo;')
        self.assert_warnings(self.MESSAGE)

    def test_create_with__proto__(self):
        """Test that creating a object literals with `__proto__` properties
        is not flagged."""

        self.run_script('var obj = {__proto__: foo};')
        self.run_script('var obj = {"__proto__": foo};')
        self.assert_silent()

    def test_setPrototypeOf(self):
        """Test that changes to object prototypes via `Object.setPrototypeOf`
        are flagged."""

        self.run_script('Object.setPrototypeOf(obj, foo)')
        self.assert_warnings(self.MESSAGE)
Example #8
0
    def test_security_prefs(self, branch):
        """Test that preference branches flagged as security issues."""

        # Check that instances not at the start of the string aren't
        # flagged.
        self.run_script('foo("thing, stuff, bleh.{0}")'.format(branch))
        self.assert_silent()

        self.run_script('foo("{0}thing")'.format(branch))
        self.assert_warnings({
            'description':
            Matches('severe security implications'),
            'signing_help':
            Matches('by exception only'),
            'signing_severity':
            'high'
        })
Example #9
0
    def test_innerHTML_script(self, fragment):
        """Test that innerHTML assignments containing <script> nodes are
        flagged."""

        self.set_html("'{0}'".format(fragment))

        self.assert_warnings({
            'id': (Exists(), 'set_%s' % self.method, 'script_assignment'),
            'message':
            Contains('Scripts'),
            'description':
            Matches('should not be used'),
            'signing_help':
            Matches('avoid including JavaScript'),
            'signing_severity':
            'medium'
        })
Example #10
0
    def test_innerHTML_event(self):
        """Test that innerHTML assignments containing event listeners
        are flagged."""

        self.set_html(""" '<a onclick="doStuff()">Hello.</a>' """)

        self.assert_warnings({
            'id': (Exists(), 'set_%s' % self.method, 'event_assignment'),
            'message':
            Contains('Event handler'),
            'description':
            Matches('addEventListener'),
            'signing_help':
            Matches('avoid including JavaScript'),
            'signing_severity':
            'medium'
        })
Example #11
0
    def test_contentScript_dynamic(self, code):
        """Test that assigning a dynamic value to a content script results
        in a warning."""

        self.run_script(code)
        self.assert_warnings({
            'id': (Exists(), 'contentScript', 'set_non_literal'),
            'message':
            '`contentScript` properties should not be used',
            'description':
            Matches('dynamic values is dangerous and '
                    'error-prone'),
            'signing_help':
            Matches('do not use'),
            'signing_severity':
            'high'
        })
Example #12
0
    def test_proxy_filter(self):
        """Test that uses of proxy filters are flagged."""

        self.run_script("""
            Cc[thing].getService(Ci.nsIProtocolProxyService).registerFilter(
                filter);
        """)
        self.assert_warnings({
            'id':
            Contains('nsIProtocolProxyService.registerFilter'),
            'description':
            Matches('direct arbitrary network traffic'),
            'signing_help':
            Matches('must undergo manual code review'),
            'signing_severity':
            'low'
        })
Example #13
0
    def test_synchronous_sql(self, code):
        """Test that the use of synchronous Storage APIs is raised as a
        performance issue."""

        self.run_script(code)
        self.assert_warnings({
            'description': Matches(r'Sqlite\.jsm.*`executeAsync`')
        })
Example #14
0
    def test_shallow_wrappers(self):
        """Test that the use of shallow wrappers results in a signing
        warning."""

        self.run_script('XPCNativeWrapper(foo, "bar");')

        self.assert_warnings({
            'id': (Exists(), 'xpcnativewrapper', 'shallow'),
            'message':
            Contains('Shallow XPCOM wrappers'),
            'description':
            Matches('Shallow XPCOM'),
            'signing_help':
            Matches('second and subsequent arguments'),
            'signing_severity':
            'high'
        })
Example #15
0
    def test_nsISound_play(self):
        """Test that `nsISound.play` is flagged for performance issues."""

        self.run_script('Cc[""].getService(Ci.nsISound).play(foo)')

        self.assert_warnings({
            'id': Contains('nsISound.play'),
            'description': Matches('synchronous.*freezes.*HTML5 audio'),
        })
Example #16
0
    def test_nsIAccessibleRetrieval(self):
        """Test that the entire `nsIAccessibleRetrieval` interface is
        flagged."""

        self.run_script('foo.QueryInterface(Ci.nsIAccessibleRetrieval)')

        self.assert_warnings({
            'id': Contains('nsIAccessibleRetrieval'),
            'description': Matches('performance degradation'),
        })
Example #17
0
    def test_nsIDNSService_resolve(self):
        """Test that `nsIDNSService.resolve` is flagged for performance
        issues."""

        self.run_script('Cc[""].getService(Ci.nsIDNSService).resolve(foo)')

        self.assert_warnings({
            'id': Contains('nsIDNSService.resolve'),
            'description': Matches('synchronous.*freeze.*asyncResolve'),
        })
Example #18
0
    def test_processNextEvent(self):
        """Test that calls to `processNextEvent` are flagged as
        performance/stability issues."""

        self.run_script('foo.processNextEvent()')
        self.assert_warnings({
            'id': Contains('**.processNextEvent'),
            'description': Matches('Spinning the event loop.*'
                                   'deadlocks.*re-?entrancy.*async'),
        })
Example #19
0
    def test_exposed_props(self):
        """Test that assignment to __exposedProps__ raises signing warnings."""

        self.run_script('obj.__exposedProps__ = {};')
        self.assert_warnings({
            'id':
            Contains('**.__exposedProps__'),
            'message':
            Contains('deprecated'),
            'description':
            Matches('`cloneInto` or `exportFunction`'),
            'signing_help':
            Matches('expose APIs'),
            'signing_severity':
            'high'
        })

        # Test that just getting the property is not flagged.
        self.setup_err()
        self.run_script('var foo = obj.__exposedProps__;')
        self.assert_silent()
Example #20
0
    def test_nsIProcess(self, script):
        """Test that uses of nsIProcess are flagged."""

        self.run_script(script)
        self.assert_warnings({
            'message':
            Contains('nsIProcess is potentially dangerous'),
            'signing_severity':
            'high',
            'signing_help':
            Matches('alternatives to directly launching '
                    'executables')
        })
Example #21
0
    def test_open_sync(self, get_xhr, arg):
        """Test that the `open` method is flagged when called with a falsy
        third argument."""

        self.run_script('let xhr = {get_xhr};'
                        'xhr.open(method, url, {arg});'
                        .format(arg=arg, get_xhr=get_xhr))

        self.assert_warnings({
            'id': Contains('nsIXMLHttpRequest.open'),
            'description': Matches('Synchronous.*serious UI performance '
                                   'problems'),
        })
Example #22
0
    def test_dynamic_sql(self, script):
        """Test that the execution of SQL statements using dynamic values
        raises a warning."""

        warning = {'id': Contains('executeSimpleSQL_dynamic'),
                   'description': Matches('dynamic parameter binding')}

        # Unknown value.
        self.run_script(script.format(code='"" + foo'))
        self.assert_warnings(warning)

        # Static string.
        self.setup_err()
        self.run_script(script.format(code='"SELECT ?"'))
        self.assert_no_warnings(warning)
Example #23
0
class TestEval(TestCase):
    """Tests that unsafe uses of eval and similar functions are flagged."""

    BASE_MESSAGE = {
        'id': ('javascript', 'dangerous_global', 'eval'),
        'description': Matches('Evaluation of strings as code'),
        'signing_help': Matches('avoid evaluating strings'),
        'signing_severity': 'high'
    }

    @pytest.fixture(params=('eval({code})', 'Function({code})',
                            'Function("foo", {code})'))
    def eval_pattern(self, request):
        return request.param

    def check_eval_literal(self, pattern):
        """Test that evaluating a literal results in the appropriate warnings
        for the literal's contents."""

        CODE = """'XPCNativeWrapper(foo, "bar")'"""

        scripts = (
            # Call eval directly.
            pattern.format(code=CODE),

            # Save to a variable first.
            ('var fooThing = {code}; '.format(code=CODE) +
             pattern.format(code='fooThing')),
        )

        for script in scripts:
            self.setup_err()
            self.run_script(script)
            self.assert_warnings(
                {'id': (Exists(), 'xpcnativewrapper', 'shallow')})

    @parametrize('arg', ('"foo"', 'foo'))
    def test_eval(self, eval_pattern, arg):
        """Test that any use of eval results in a warning."""

        self.run_script(eval_pattern.format(code=arg))
        self.assert_warnings(self.BASE_MESSAGE)

    def test_eval_literal(self, eval_pattern):
        """Test that evaluating a literal results in the appropriate warnings
        for the literal's contents."""

        self.check_eval_literal(eval_pattern)

    # The branching factor for these will make your head spin. And it doesn't
    # even tests things declared in branches. Complete coverage is fine, and
    # all, but this is perhaps going a bit overboard. And underboard.

    @pytest.fixture(params=('setTimeout({code}, 100)',
                            'setInterval({code}, 100)'))
    def setTimeout_pattern(self, request):
        """Yields several variants of `setTimeout` and `setInterval`, each with
        a `{code}` format string replacement for its first parameter."""
        return request.param

    callables = [
        pattern.format(callable=callable)
        for callable, pattern in itertools.product((
            'function() {}', 'function x() {}', 'function* () {}',
            'function* x() {}', '() => {}', '() => 1', 'declared_function',
            'declared_generator'), ('({callable})', '({callable}).bind()'))
    ]

    @pytest.fixture(params=callables)
    def function_ish(self, request):
        """Yields a number of callable expression types, along with their
        counterparts returned by `.bind()`."""
        return request.param

    def test_setTimeout_function(self, setTimeout_pattern, function_ish):
        """Test that setTimeout and setInterval called with function arguments
        is silent."""

        base_script = '''
            function declared_function() {}
            function* declared_generator() {}
        '''

        self.run_script(base_script +
                        setTimeout_pattern.format(code=function_ish))
        self.assert_silent()

    @parametrize('declare',
                 ('var thing = {callable};', 'const thing = {callable};',
                  'thing = {callable};', 'let thing = {callable};'))
    def test_setTimeout_var_function(self, setTimeout_pattern, function_ish,
                                     declare):

        base_script = '''
            function declared_function() {}
            function* declared_generator() {}
        '''
        declaration = declare.format(callable=function_ish)

        self.run_script(base_script + declaration +
                        setTimeout_pattern.format(code='thing'))

        self.assert_silent()

    def test_setTimeout_literal(self, setTimeout_pattern):
        """Test that evaluating a literal results in the appropriate warnings
        for the literal's contents."""

        self.check_eval_literal(setTimeout_pattern)

    def test_setTimeout_dynamic(self, setTimeout_pattern):
        """Test that running setTimeout or setInterval with a dynamic,
        non-function value results in the appropriate warning."""

        self.run_script(setTimeout_pattern.format(code='foo'))

        self.assert_warnings(
            dict(
                self.BASE_MESSAGE,
                description=Matches('function expressions as their first arg'),
                signing_help=Matches('do not ever call.*string arguments')))

    @parametrize(
        'pattern',
        ('foo({{contentScript: {code}}})', 'x.contentScript = {code};'))
    def test_contentScript_literal(self, pattern):
        """Test that evaluating a literal results in the appropriate warnings
        for the literal's contents."""

        # FIXME: These messages are currently missing the appropriate
        # context.
        self.skip_sanity_check()

        self.check_eval_literal(pattern)

    @parametrize('code',
                 ('foo({contentScript: foo})', 'x.contentScript = foo;'))
    def test_contentScript_dynamic(self, code):
        """Test that assigning a dynamic value to a content script results
        in a warning."""

        self.run_script(code)
        self.assert_warnings({
            'id': (Exists(), 'contentScript', 'set_non_literal'),
            'message':
            '`contentScript` properties should not be used',
            'description':
            Matches('dynamic values is dangerous and '
                    'error-prone'),
            'signing_help':
            Matches('do not use'),
            'signing_severity':
            'high'
        })
Example #24
0
    def test_other_prefs(self, branch):
        """Test that less security-sensitive preferences are flagged."""

        self.run_script('foo("{0}bar")'.format(branch))
        self.assert_warnings({'message': Matches('unsafe preference branch')})
Example #25
0
    def test_unsafeWindow(self):
        """Test that access to `unsafeWindow` is flagged."""

        self.run_script('var foo = unsafeWindow.bar;')
        self.assert_warnings(
            {'description': Matches('unsafeWindow is insecure')})