Repository: streamlit/streamlit

Issue:
Update Streamlit hashlib usage for FIPS-Compliant Systems and Security Best Practices
### Checklist

- [X] I have searched the [existing issues](https://github.com/streamlit/streamlit/issues) for similar feature requests.
- [X] I added a descriptive title and summary to this issue.

### Summary

The usage of streamlit with FIPS-Compliant Systems are in the current streamlit version not possible. This is caused by the following two lines: 
https://github.com/streamlit/streamlit/blob/873a52ebf8a418555216c88278389a128dd989ed/lib/streamlit/runtime/forward_msg_cache.py#L54
https://github.com/streamlit/streamlit/blob/873a52ebf8a418555216c88278389a128dd989ed/lib/streamlit/watcher/util.py#L58

These lines cause compatibility issues with FIPS-compliant systems, leading to the error message `ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS`.

Furthermore, the usage of MD5 for security purposes is strongly discouraged due to its known hash collision weaknesses. See the warning on the [hashlib documentation](https://docs.python.org/3/library/hashlib.html#hashlib.md5):
> Warning Some algorithms have known hash collision weaknesses (including MD5 and SHA1). Refer to [Attacks on cryptographic hash algorithms](https://en.wikipedia.org/wiki/Cryptographic_hash_function#Attacks_on_cryptographic_hash_algorithms) and the [hashlib-seealso](https://docs.python.org/3/library/hashlib.html#hashlib-seealso) section at the end of this document. 


### Why?

_No response_

### How?

Since the usage of md5 in the two cases are not used for security purposes, the fix is quite simple. Simply change the initialisation of md5 with `usedforsecurity=False`.

```python
import hashlib

# Current code:
md5_hash = hashlib.md5(data)

# Proposed change to enhance security and FIPS compliance:
md5_hash = hashlib.md5(data, usedforsecurity=False)
```

I'll attach a pull request fixing this. I feel quite certain that this fix will have no side effects other than the system becoming FIPS-compliant.

### Additional Context

_No response_


Discussion:
**To help Streamlit prioritize this feature, react with a 👍 (thumbs up emoji) to the initial post.**

Your vote helps us identify which enhancements matter most to our users.

Resolving patch:
diff --git a/lib/streamlit/runtime/forward_msg_cache.py b/lib/streamlit/runtime/forward_msg_cache.py
--- a/lib/streamlit/runtime/forward_msg_cache.py
+++ b/lib/streamlit/runtime/forward_msg_cache.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import hashlib
+import sys
 from typing import TYPE_CHECKING, Dict, List, MutableMapping, Optional
 from weakref import WeakKeyDictionary
 
@@ -51,7 +52,10 @@ def populate_hash_if_needed(msg: ForwardMsg) -> str:
         msg.ClearField("metadata")
 
         # MD5 is good enough for what we need, which is uniqueness.
-        hasher = hashlib.md5()
+        if sys.version_info >= (3, 9):
+            hasher = hashlib.md5(usedforsecurity=False)
+        else:
+            hasher = hashlib.md5()
         hasher.update(msg.SerializeToString())
         msg.hash = hasher.hexdigest()
 
diff --git a/lib/streamlit/watcher/util.py b/lib/streamlit/watcher/util.py
--- a/lib/streamlit/watcher/util.py
+++ b/lib/streamlit/watcher/util.py
@@ -20,6 +20,7 @@
 
 import hashlib
 import os
+import sys
 import time
 from pathlib import Path
 from typing import Optional
@@ -55,7 +56,10 @@ def calc_md5_with_blocking_retries(
     else:
         content = _get_file_content_with_blocking_retries(path)
 
-    md5 = hashlib.md5()
+    if sys.version_info >= (3, 9):
+        md5 = hashlib.md5(usedforsecurity=False)
+    else:
+        md5 = hashlib.md5()
     md5.update(content)
 
     # Use hexdigest() instead of digest(), so it's easier to debug.


Test patch: