# -*- coding:utf-8 -*- # # Copyright (C) 2018 [Victor Torre](https://github.com/ehooo) # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import ast import bandit from bandit.core import test_properties as test def keywords2dict(keywords): kwargs = {} for node in keywords: if isinstance(node, ast.keyword): kwargs[node.arg] = node.value return kwargs @test.checks('Call') @test.test_id('B610') def django_extra_used(context): """**B610: Potential SQL injection on extra function** .. seealso:: - https://docs.djangoproject.com/en/dev/topics/ security/#sql-injection-protection .. versionadded:: 1.5.0 """ description = "Use of extra potential SQL attack vector." if context.call_function_name == 'extra': kwargs = keywords2dict(context.node.keywords) args = context.node.args if args: if len(args) >= 1: kwargs['select'] = args[0] if len(args) >= 2: kwargs['where'] = args[1] if len(args) >= 3: kwargs['params'] = args[2] if len(args) >= 4: kwargs['tables'] = args[3] if len(args) >= 5: kwargs['order_by'] = args[4] if len(args) >= 6: kwargs['select_params'] = args[5] insecure = False for key in ['where', 'tables']: if key in kwargs: if isinstance(kwargs[key], ast.List): for val in kwargs[key].elts: if not isinstance(val, ast.Str): insecure = True break else: insecure = True break if not insecure and 'select' in kwargs: if isinstance(kwargs['select'], ast.Dict): for k in kwargs['select'].keys: if not isinstance(k, ast.Str): insecure = True break if not insecure: for v in kwargs['select'].values: if not isinstance(v, ast.Str): insecure = True break else: insecure = True if insecure: return bandit.Issue( severity=bandit.MEDIUM, confidence=bandit.MEDIUM, text=description ) @test.checks('Call') @test.test_id('B611') def django_rawsql_used(context): """**B611: Potential SQL injection on RawSQL function** .. seealso:: - https://docs.djangoproject.com/en/dev/topics/ security/#sql-injection-protection .. versionadded:: 1.5.0 """ description = "Use of RawSQL potential SQL attack vector." if context.is_module_imported_like('django.db.models'): if context.call_function_name == 'RawSQL': sql = context.node.args[0] if not isinstance(sql, ast.Str): return bandit.Issue( severity=bandit.MEDIUM, confidence=bandit.MEDIUM, text=description )