#1064 pyscg ensure 06_logging has an rfc compliant audit log example#1079
#1064 pyscg ensure 06_logging has an rfc compliant audit log example#1079BartKaras1128 wants to merge 2 commits intoossf:mainfrom
Conversation
Signed-off-by: Bartlomiej Karas <bartlomiej.karas@ericsson.com>
Signed-off-by: Bartlomiej Karas <moezarts@gmail.com>
myteron
left a comment
There was a problem hiding this comment.
suggested an alternative compliant02.py cod example
| @@ -1,6 +1,6 @@ | |||
| # pyscg-0020: Implement Informative Event Logging | |||
| # pyscg-0020: Insufficient Logging | |||
There was a problem hiding this comment.
@BartKaras1128
rule still has the old title, see new one pyscg-0020: Implement Informative Event Logging
looks like you started out from an outdated branch?
| import logging | ||
|
|
||
| logging.basicConfig( | ||
| format="%(asctime)s %(levelname)s event=%(message)s", | ||
| datefmt="%Y-%m-%dT%H:%M:%S", | ||
| level=logging.INFO, | ||
| ) | ||
| _audit = logging.getLogger("audit") | ||
|
|
||
|
|
||
| def login(username: str, password: str) -> bool: | ||
| """Authenticate user with audit logging""" | ||
| # TODO: use a proper credential store | ||
| if username == "admin" and password == "s3cr3t": | ||
| _audit.info("login_success user=%s", username) | ||
| return True | ||
| _audit.warning("login_failed user=%s", username) | ||
| # TODO: forward logs to a remote logging service in production | ||
| return False |
There was a problem hiding this comment.
Here a code example that is a little closer to the rfc with timestamps and such but still missing some stuff added as TODO.
| import logging | |
| logging.basicConfig( | |
| format="%(asctime)s %(levelname)s event=%(message)s", | |
| datefmt="%Y-%m-%dT%H:%M:%S", | |
| level=logging.INFO, | |
| ) | |
| _audit = logging.getLogger("audit") | |
| def login(username: str, password: str) -> bool: | |
| """Authenticate user with audit logging""" | |
| # TODO: use a proper credential store | |
| if username == "admin" and password == "s3cr3t": | |
| _audit.info("login_success user=%s", username) | |
| return True | |
| _audit.warning("login_failed user=%s", username) | |
| # TODO: forward logs to a remote logging service in production | |
| return False | |
| # SPDX-FileCopyrightText: OpenSSF project contributors | |
| # SPDX-License-Identifier: MIT | |
| """Compliant Code Example""" | |
| import json | |
| import logging | |
| from datetime import datetime, timezone | |
| logging.basicConfig(format="%(message)s", level=logging.INFO) | |
| def audit_log(event: str, user: str, outcome: str) -> None: | |
| """Write a simple audit log entry in JSON format""" | |
| # TODO: add hostname, app_name, proc_id per RFC 5424 | |
| # TODO: forward logs to a remote logging service | |
| # TODO: sanitize user input to prevent log injection, see pyscg-0022 | |
| entry = { | |
| "timestamp": datetime.now(timezone.utc).isoformat(timespec="milliseconds"), | |
| "event": event, | |
| "user": user, | |
| "outcome": outcome, | |
| } | |
| logging.info("%s", json.dumps(entry)) | |
| def login(username: str, password: str) -> bool: | |
| """Authenticate user with audit logging""" | |
| # TODO: use a proper credential store, see pyscg-0041 | |
| if username == "admin" and password == "s3cr3t": | |
| audit_log("login", username, "success") | |
| return True | |
| audit_log("login", username, "failure") | |
| return False | |
| ##################### | |
| # Trying to exploit above code example | |
| ##################### | |
| login("admin", "wrong_password") | |
| login("admin", "password123!") | |
| login("admin", "s3cr3t") |
|
|
||
| ## Compliant Solution (Audit Logging) | ||
|
|
||
| The `compliant02.py` solution configures a `logging.Formatter` with timestamp, severity, and a structured event message. Both successful and failed authentication attempts are logged with the event type and username, without exposing sensitive data such as the password. Successful logins are logged at `INFO` level and failures at `WARNING` level. |
There was a problem hiding this comment.
In case you do adapt the code then we will have to explain why we use json instead of strictly following the rfc. Here a draft for that explanation:
RFC 5424 defines the standard transport for system logs without JSON. This guide recommends using structured JSON payloads to ensure logs are machine-readable for automated security analysis instead plain-text as defined in RFC 5424 as supported by:
Added 2 new code examples for auditing a failed authentication attempt, and I added a section to the README explaining it for pyscg-0020