Uploaded image for project: 'SonarPython'
  1. SonarPython
  2. SONARPY-668

Rule S4502: Disabling CSRF protection is security-sensitive

    Details

    • Type: New Feature
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 2.10
    • Component/s: Rules
    • Labels:
      None

      Description

      Implements: https://jira.sonarsource.com/browse/RSPEC-5792

      Detection pattern, code examples:
      https://github.com/SonarSource/security-expected-issues/tree/master/python/rules/hotspots/RSPEC-4502

      For a Django application, this rule should be triggered when

      • the MIDDLEWARE array doesn't have an element with this value: django.middleware.csrf.CsrfViewMiddleware
        MIDDLEWARE = [
            'django.middleware.security.SecurityMiddleware',
            'django.contrib.sessions.middleware.SessionMiddleware',
            'django.middleware.common.CommonMiddleware',
            'django.contrib.auth.middleware.AuthenticationMiddleware',
            'django.contrib.messages.middleware.MessageMiddleware',
            'django.middleware.clickjacking.XFrameOptionsMiddleware',
        ] # Sensitive: django.middleware.csrf.CsrfViewMiddleware is missing
        

        To be sure we analyze the MIDDLEWARE array of a Django application (the settings of a Django application), this rule should be triggered only if the MIDDLEWARE array has at least one string element with a value starting with django.

      • When @csrf_exempt annotation is found

      For a Flask application, this rule should be triggered when

      • app.config['WTF_CSRF_ENABLED'] is set to False
      • the CSRFProtect module is not used on the app, it is the case by default, thus should always raise except when one of these two blocks is found:
        csrf = CSRFProtect()
        csrf.init_app(app) # Compliant
        
        CSRFProtect(app) # Compliant
        

        Ideally when looking for the existence of one of these two blocks, the analysis should be cross-files, and to overcome but possible limitations of the analyzer (type inference etc...) it might be enough to not raise when csrf.init_app(app) is found (whatever the type of the first argument: it cannot be anything else from an Flask() object) or when CSRFProtect(app) call is found (same thing: whatever the type of app, check that one argument exist when calling CSRFProtect method is enough).

      • when @csrf.exempt annotation is found or csrf.exempt(simple_page) method call is found
      • when a FlaskForm has disabled the CSRF protection, three cases:
        • During the definition of the class:
             class unprotectedForm(FlaskForm):
                  class Meta:
                       csrf = False # Sensitive
          
        • During the instantiation (Flask < 0.14):
          form = TestForm(request.form, csrf_enabled=False) # Sensitive
          
        • During the instantiation (Flask >= 0.14):
          form = TestForm(request.form, meta={'csrf': False}) # Sensitive
          

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                andrey.tyukin Andrey Tyukin
                Reporter:
                eric.therond Eric Therond
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Due:
                  Created:
                  Updated:
                  Resolved: