diff --git a/src/codemodder/dependency.py b/src/codemodder/dependency.py index 1d1179e2..4a8f86c4 100644 --- a/src/codemodder/dependency.py +++ b/src/codemodder/dependency.py @@ -37,7 +37,7 @@ def __hash__(self): return hash(self.requirement) -FLaskWTF = Dependency( +FlaskWTF = Dependency( Requirement("flask-wtf~=1.2.0"), description="""\ This package integrates WTForms into Flask. WTForms provides data validation and and CSRF protection which helps harden applications. diff --git a/src/core_codemods/docs/pixee_python_flask-enable-csrf-protection.md b/src/core_codemods/docs/pixee_python_flask-enable-csrf-protection.md index bd2a6bd6..b85f6354 100644 --- a/src/core_codemods/docs/pixee_python_flask-enable-csrf-protection.md +++ b/src/core_codemods/docs/pixee_python_flask-enable-csrf-protection.md @@ -1,4 +1,9 @@ +Cross-site request forgery (CSRF) is an attack where a user is tricked by a malicious agent to submit a unintended request (e.g login requests). A common way to mitigate this issue is to embed an additional token into requests to identify requests from unauthorized locations. + Flask views using `FlaskForm` have CSRF protection enabled by default. However other views may use AJAX to perform unsafe HTTP methods. FlaskWTF provides a way to enable CSRF protection globally for all views of a Flask app. + +The changes in this codemod may require manual additions to maintain proper functionality. You need to setup either a flask `SECRET_KEY` or a `WTF_CSRF_SECRET_KEY` in you app configuration and adjust any views with HTML forms and javascript requests to include the CSRF token. See the [FlaskWTF docs](https://flask-wtf.readthedocs.io/en/1.2.x/csrf/) for examples on how to do it. + Our changes look something like this: ```diff diff --git a/src/core_codemods/flask_enable_csrf_protection.py b/src/core_codemods/flask_enable_csrf_protection.py index 0e2986c6..1f6148cb 100644 --- a/src/core_codemods/flask_enable_csrf_protection.py +++ b/src/core_codemods/flask_enable_csrf_protection.py @@ -3,18 +3,19 @@ from codemodder.codemods.api import BaseCodemod from codemodder.codemods.base_codemod import ReviewGuidance from codemodder.codemods.utils_mixin import AncestorPatternsMixin, NameResolutionMixin -from codemodder.dependency import FLaskWTF +from codemodder.dependency import FlaskWTF class FlaskEnableCSRFProtection( BaseCodemod, NameResolutionMixin, AncestorPatternsMixin ): NAME = "flask-enable-csrf-protection" - REVIEW_GUIDANCE = ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW + REVIEW_GUIDANCE = ReviewGuidance.MERGE_AFTER_REVIEW DESCRIPTION = "Uses CSRFProtect module to harden the app." SUMMARY = "Enable CSRF protection globally for a Flask app." REFERENCES = [ {"url": "https://owasp.org/www-community/attacks/csrf", "description": ""}, + {"url": "https://flask-wtf.readthedocs.io/en/1.2.x/csrf/", "description": ""}, ] def leave_SimpleStatementSuite( @@ -26,7 +27,7 @@ def leave_SimpleStatementSuite( new_stmts = self._get_new_stmts(original_node) if new_stmts: self.add_needed_import("flask_wtf.csrf", "CSRFProtect") - self.add_dependency(FLaskWTF) + self.add_dependency(FlaskWTF) self.report_change(original_node) return updated_node.with_changes(body=[*original_node.body, *new_stmts]) return updated_node @@ -42,7 +43,7 @@ def leave_SimpleStatementLine( new_stmts = self._get_new_stmts(original_node) if new_stmts: self.add_needed_import("flask_wtf.csrf", "CSRFProtect") - self.add_dependency(FLaskWTF) + self.add_dependency(FlaskWTF) self.report_change(original_node) if len(original_node.body) > 1: return updated_node.with_changes(