From 484e77abc7bcf1a98a44ce20f01a78ccf52cd307 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Tue, 23 Jan 2024 09:05:11 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=E3=82=BB=E3=82=AD=E3=83=A5=E3=83=AA?= =?UTF-8?q?=E3=83=86=E3=82=A3=E3=83=98=E3=83=83=E3=83=80=E3=83=BC=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/templates/_header.html | 34 ++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/ecs/jskult-webapp/src/templates/_header.html b/ecs/jskult-webapp/src/templates/_header.html index a0e90606..920d0beb 100644 --- a/ecs/jskult-webapp/src/templates/_header.html +++ b/ecs/jskult-webapp/src/templates/_header.html @@ -1,19 +1,41 @@ - + + + + + + + + + + + {{subtitle}} - - + + - - + + - + \ No newline at end of file From 426426b278641e8f01a0ad8f1d4660341e09459e Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Wed, 24 Jan 2024 15:11:49 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=E3=83=98=E3=83=83=E3=83=80=E3=83=BCCache-C?= =?UTF-8?q?ontrol=E3=83=BBX-Content-Type-Options=E3=83=BBStrict-Transport-?= =?UTF-8?q?Security=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/bio_api.py | 16 +++++++++++ ecs/jskult-webapp/src/controller/login.py | 16 +++++++++++ ecs/jskult-webapp/src/controller/logout.py | 7 +++++ .../src/router/session_router.py | 8 ++++++ ecs/jskult-webapp/src/templates/_header.html | 27 +++++++------------ 5 files changed, 56 insertions(+), 18 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/bio_api.py b/ecs/jskult-webapp/src/controller/bio_api.py index 2f96408a..d907fd70 100644 --- a/ecs/jskult-webapp/src/controller/bio_api.py +++ b/ecs/jskult-webapp/src/controller/bio_api.py @@ -79,6 +79,14 @@ def search_bio_data( 'data': data, 'count': bio_sales_lot_count }) + + # X-Content-Type-Optionsヘッダー追加 + json_response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + json_response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + json_response.headers['Cache-Control'] = 'private' + # クッキーも書き換え json_response.set_cookie( key='session', @@ -152,6 +160,14 @@ async def download_bio_data( 'status': 'ok', 'download_url': download_file_url }) + + # X-Content-Type-Optionsヘッダー追加 + json_response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + json_response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + json_response.headers['Cache-Control'] = 'private' + json_response.set_cookie( key='session', value=session.session_key, diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index c8a5663c..3edf877d 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -113,6 +113,14 @@ def login( status_code=status.HTTP_303_SEE_OTHER, headers={'session_key': session_key} ) + + # X-Content-Type-Optionsヘッダー追加 + response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + response.headers['Cache-Control'] = 'private' + return response @@ -170,4 +178,12 @@ def sso_authorize( status_code=status.HTTP_303_SEE_OTHER, headers={'session_key': session_key} ) + + # X-Content-Type-Optionsヘッダー追加 + response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + response.headers['Cache-Control'] = 'private' + return response diff --git a/ecs/jskult-webapp/src/controller/logout.py b/ecs/jskult-webapp/src/controller/logout.py index 76d9ef60..c11e10d0 100644 --- a/ecs/jskult-webapp/src/controller/logout.py +++ b/ecs/jskult-webapp/src/controller/logout.py @@ -54,4 +54,11 @@ def logout_view( if session: session_service.delete_session(session) + # X-Content-Type-Optionsヘッダー追加 + template_response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + template_response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + template_response.headers['Cache-Control'] = 'private' + return template_response diff --git a/ecs/jskult-webapp/src/router/session_router.py b/ecs/jskult-webapp/src/router/session_router.py index a4a28e25..4f6ffe2f 100644 --- a/ecs/jskult-webapp/src/router/session_router.py +++ b/ecs/jskult-webapp/src/router/session_router.py @@ -103,6 +103,14 @@ class AfterSetCookieSessionRoute(MeDaCaRoute): """事後処理として、セッションキーをcookieに設定するカスタムルートハンドラー""" async def post_process_route(self, request: Request, response: Response): response = await super().post_process_route(request, response) + + # X-Content-Type-Optionsヘッダー追加 + response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + response.headers['Cache-Control'] = 'private' + session_key = response.headers.get('session_key', None) # セッションキーがない場合はセットせずに返す if session_key is None: diff --git a/ecs/jskult-webapp/src/templates/_header.html b/ecs/jskult-webapp/src/templates/_header.html index 920d0beb..458df9fb 100644 --- a/ecs/jskult-webapp/src/templates/_header.html +++ b/ecs/jskult-webapp/src/templates/_header.html @@ -1,15 +1,9 @@ - + + - - - - - - - - - \ No newline at end of file + + + + + + + \ No newline at end of file From a435c51bc75177eebb00f43a752b9ceb8e66ef3f Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Thu, 25 Jan 2024 16:08:05 +0900 Subject: [PATCH 3/8] =?UTF-8?q?X-Frame-Options=E3=83=98=E3=83=83=E3=83=80?= =?UTF-8?q?=E3=83=BC=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/bio_api.py | 6 +++++- ecs/jskult-webapp/src/controller/login.py | 4 ++++ ecs/jskult-webapp/src/controller/logout.py | 2 ++ ecs/jskult-webapp/src/router/session_router.py | 2 ++ ecs/jskult-webapp/src/templates/_header.html | 16 ++-------------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/bio_api.py b/ecs/jskult-webapp/src/controller/bio_api.py index d907fd70..bbb06b69 100644 --- a/ecs/jskult-webapp/src/controller/bio_api.py +++ b/ecs/jskult-webapp/src/controller/bio_api.py @@ -79,7 +79,9 @@ def search_bio_data( 'data': data, 'count': bio_sales_lot_count }) - + + # X-Frame-Optionsヘッダー追加 + json_response.headers['X-Frame-Options'] = 'DENY' # X-Content-Type-Optionsヘッダー追加 json_response.headers['X-Content-Type-Options'] = 'nosniff' # Strict-Transport-Securityヘッダー追加 @@ -161,6 +163,8 @@ async def download_bio_data( 'download_url': download_file_url }) + # X-Frame-Optionsヘッダー追加 + json_response.headers['X-Frame-Options'] = 'DENY' # X-Content-Type-Optionsヘッダー追加 json_response.headers['X-Content-Type-Options'] = 'nosniff' # Strict-Transport-Securityヘッダー追加 diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index 3edf877d..bcc48fe1 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -114,6 +114,8 @@ def login( headers={'session_key': session_key} ) + # X-Frame-Optionsヘッダー追加 + response.headers['X-Frame-Options'] = 'DENY' # X-Content-Type-Optionsヘッダー追加 response.headers['X-Content-Type-Options'] = 'nosniff' # Strict-Transport-Securityヘッダー追加 @@ -179,6 +181,8 @@ def sso_authorize( headers={'session_key': session_key} ) + # X-Frame-Optionsヘッダー追加 + response.headers['X-Frame-Options'] = 'DENY' # X-Content-Type-Optionsヘッダー追加 response.headers['X-Content-Type-Options'] = 'nosniff' # Strict-Transport-Securityヘッダー追加 diff --git a/ecs/jskult-webapp/src/controller/logout.py b/ecs/jskult-webapp/src/controller/logout.py index c11e10d0..99ee8813 100644 --- a/ecs/jskult-webapp/src/controller/logout.py +++ b/ecs/jskult-webapp/src/controller/logout.py @@ -54,6 +54,8 @@ def logout_view( if session: session_service.delete_session(session) + # X-Frame-Optionsヘッダー追加 + template_response.headers['X-Frame-Options'] = 'DENY' # X-Content-Type-Optionsヘッダー追加 template_response.headers['X-Content-Type-Options'] = 'nosniff' # Strict-Transport-Securityヘッダー追加 diff --git a/ecs/jskult-webapp/src/router/session_router.py b/ecs/jskult-webapp/src/router/session_router.py index 4f6ffe2f..9672d23b 100644 --- a/ecs/jskult-webapp/src/router/session_router.py +++ b/ecs/jskult-webapp/src/router/session_router.py @@ -104,6 +104,8 @@ class AfterSetCookieSessionRoute(MeDaCaRoute): async def post_process_route(self, request: Request, response: Response): response = await super().post_process_route(request, response) + # X-Frame-Optionsヘッダー追加 + response.headers['X-Frame-Options'] = 'DENY' # X-Content-Type-Optionsヘッダー追加 response.headers['X-Content-Type-Options'] = 'nosniff' # Strict-Transport-Securityヘッダー追加 diff --git a/ecs/jskult-webapp/src/templates/_header.html b/ecs/jskult-webapp/src/templates/_header.html index 458df9fb..db30bfb4 100644 --- a/ecs/jskult-webapp/src/templates/_header.html +++ b/ecs/jskult-webapp/src/templates/_header.html @@ -3,21 +3,9 @@ - - - - - - - - {{subtitle}} - - + + From 46fa3844ab909f255861ffdf7aabee9e7ce39ee8 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Mon, 29 Jan 2024 13:46:05 +0900 Subject: [PATCH 4/8] =?UTF-8?q?SRI=E3=81=AE=E6=B3=A8=E6=84=8F=E4=BA=8B?= =?UTF-8?q?=E9=A0=85=E3=83=BBhash=E3=82=92=E7=94=9F=E6=88=90=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E8=BF=BD=E5=8A=A0=E8=A8=98=E8=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ecs/jskult-webapp/README.md b/ecs/jskult-webapp/README.md index 97632b8f..e85ed943 100644 --- a/ecs/jskult-webapp/README.md +++ b/ecs/jskult-webapp/README.md @@ -195,3 +195,16 @@ - コントローラーのrouter変数が、`router.route_class = Authenticate`となっている場合、以下の動きをする - リクエスト到達時にセッションの有無をチェックする - レスポンス時、クッキーにセッションキーを登録する + +## ヘッダーにSRI設定・生成方法 +- インポートされたソースに更新したら、SRIのintegrity hashも更新すること + - ソースはローカルにある場合下記の`bash`コマンドでハッシュ生成できる: + ``` + cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A + ``` + - 外部ソース *(リンクから)* 使用する場合は下記のMDNオンラインツールでハッシュ生成できる: + [SRI Hash Generator](https://www.srihash.org/) + - SRIサンプル: + ``` + + ``` From 3feca4d25c793453a76b59e9fc1a16a41fd3a29c Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Mon, 29 Jan 2024 16:50:31 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=E3=83=9F=E3=83=89=E3=83=AB=E3=82=A6?= =?UTF-8?q?=E3=82=A7=E3=82=A2=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/bio_api.py | 18 ------- ecs/jskult-webapp/src/controller/login.py | 18 ------- ecs/jskult-webapp/src/controller/logout.py | 9 ---- ecs/jskult-webapp/src/main.py | 5 ++ ecs/jskult-webapp/src/middleware/__init__.py | 0 .../src/middleware/middleware.py | 47 +++++++++++++++++++ .../src/router/session_router.py | 9 ---- 7 files changed, 52 insertions(+), 54 deletions(-) create mode 100644 ecs/jskult-webapp/src/middleware/__init__.py create mode 100644 ecs/jskult-webapp/src/middleware/middleware.py diff --git a/ecs/jskult-webapp/src/controller/bio_api.py b/ecs/jskult-webapp/src/controller/bio_api.py index bbb06b69..4989a50d 100644 --- a/ecs/jskult-webapp/src/controller/bio_api.py +++ b/ecs/jskult-webapp/src/controller/bio_api.py @@ -80,15 +80,6 @@ def search_bio_data( 'count': bio_sales_lot_count }) - # X-Frame-Optionsヘッダー追加 - json_response.headers['X-Frame-Options'] = 'DENY' - # X-Content-Type-Optionsヘッダー追加 - json_response.headers['X-Content-Type-Options'] = 'nosniff' - # Strict-Transport-Securityヘッダー追加 - json_response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' - # Cache-Controlヘッダー追加 - json_response.headers['Cache-Control'] = 'private' - # クッキーも書き換え json_response.set_cookie( key='session', @@ -162,15 +153,6 @@ async def download_bio_data( 'status': 'ok', 'download_url': download_file_url }) - - # X-Frame-Optionsヘッダー追加 - json_response.headers['X-Frame-Options'] = 'DENY' - # X-Content-Type-Optionsヘッダー追加 - json_response.headers['X-Content-Type-Options'] = 'nosniff' - # Strict-Transport-Securityヘッダー追加 - json_response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' - # Cache-Controlヘッダー追加 - json_response.headers['Cache-Control'] = 'private' json_response.set_cookie( key='session', diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index bcc48fe1..5c8d904e 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -114,15 +114,6 @@ def login( headers={'session_key': session_key} ) - # X-Frame-Optionsヘッダー追加 - response.headers['X-Frame-Options'] = 'DENY' - # X-Content-Type-Optionsヘッダー追加 - response.headers['X-Content-Type-Options'] = 'nosniff' - # Strict-Transport-Securityヘッダー追加 - response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' - # Cache-Controlヘッダー追加 - response.headers['Cache-Control'] = 'private' - return response @@ -180,14 +171,5 @@ def sso_authorize( status_code=status.HTTP_303_SEE_OTHER, headers={'session_key': session_key} ) - - # X-Frame-Optionsヘッダー追加 - response.headers['X-Frame-Options'] = 'DENY' - # X-Content-Type-Optionsヘッダー追加 - response.headers['X-Content-Type-Options'] = 'nosniff' - # Strict-Transport-Securityヘッダー追加 - response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' - # Cache-Controlヘッダー追加 - response.headers['Cache-Control'] = 'private' return response diff --git a/ecs/jskult-webapp/src/controller/logout.py b/ecs/jskult-webapp/src/controller/logout.py index 99ee8813..76d9ef60 100644 --- a/ecs/jskult-webapp/src/controller/logout.py +++ b/ecs/jskult-webapp/src/controller/logout.py @@ -54,13 +54,4 @@ def logout_view( if session: session_service.delete_session(session) - # X-Frame-Optionsヘッダー追加 - template_response.headers['X-Frame-Options'] = 'DENY' - # X-Content-Type-Optionsヘッダー追加 - template_response.headers['X-Content-Type-Options'] = 'nosniff' - # Strict-Transport-Securityヘッダー追加 - template_response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' - # Cache-Controlヘッダー追加 - template_response.headers['Cache-Control'] = 'private' - return template_response diff --git a/ecs/jskult-webapp/src/main.py b/ecs/jskult-webapp/src/main.py index 9a19d97b..61a8170f 100644 --- a/ecs/jskult-webapp/src/main.py +++ b/ecs/jskult-webapp/src/main.py @@ -10,6 +10,7 @@ from src.controller import (bio, bio_api, healthcheck, login, logout, from src.core import task from src.error.exception_handler import http_exception_handler from src.error.exceptions import UnexpectedException +from src.middleware.middleware import ErrorHandlingMiddleware, SecurityHeadersMiddleware app = FastAPI(openapi_url=None) @@ -42,5 +43,9 @@ app.add_exception_handler(status.HTTP_403_FORBIDDEN, http_exception_handler) # サーバーエラーが発生した場合のハンドラー。HTTPExceptionではハンドリングできないため、個別に設定 app.add_exception_handler(UnexpectedException, http_exception_handler) +# セキュリティヘッダー設定・サーバーエラーや認証失敗はミドルウェアで処理する +app.add_middleware(ErrorHandlingMiddleware) +app.add_middleware(SecurityHeadersMiddleware) + # サーバー起動時のイベント app.add_event_handler('startup', task.create_start_app_handler()) diff --git a/ecs/jskult-webapp/src/middleware/__init__.py b/ecs/jskult-webapp/src/middleware/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-webapp/src/middleware/middleware.py b/ecs/jskult-webapp/src/middleware/middleware.py new file mode 100644 index 00000000..64ffeb0b --- /dev/null +++ b/ecs/jskult-webapp/src/middleware/middleware.py @@ -0,0 +1,47 @@ +from fastapi import Request, Response, status +from fastapi.responses import JSONResponse +from starlette.middleware.base import BaseHTTPMiddleware + +class SecurityHeadersMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request, call_next): + response = await call_next(request) + # X-Frame-Optionsヘッダー追加 + response.headers['X-Frame-Options'] = 'DENY' + # X-Content-Type-Optionsヘッダー追加 + response.headers['X-Content-Type-Options'] = 'nosniff' + # Strict-Transport-Securityヘッダー追加 + response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' + # Cache-Controlヘッダー追加 + response.headers['Cache-Control'] = 'private' + return response + +class ErrorHandlingMiddleware(BaseHTTPMiddleware): + # エラーハンドリングをするミドルウェア + # API内で発生したエラーをキャッチして処理を施す + + async def dispatch(self, request: Request, call_next) -> Response: + try: + response: Response = await call_next(request) + except TypeError as e: + response = JSONResponse( + {"msg": "TypeError:内容を確認してもう一度データ挿入をしてください。"}, + status.HTTP_404_NOT_FOUND, + ) + except TimeoutError as e: + response = JSONResponse( + {"msg": "TimeoutError:タイムアウトエラーが発生しました。"}, + status.HTTP_408_REQUEST_TIMEOUT, + ) + except RuntimeError as e: + response = JSONResponse( + {"msg": "RuntimeError:ランタイムエラーが発生しました。"}, + status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + except Exception as e: + response = JSONResponse( + {"msg": "Exception:基底クラスエラーが発生しました。"}, + status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + return response + + diff --git a/ecs/jskult-webapp/src/router/session_router.py b/ecs/jskult-webapp/src/router/session_router.py index 9672d23b..30690590 100644 --- a/ecs/jskult-webapp/src/router/session_router.py +++ b/ecs/jskult-webapp/src/router/session_router.py @@ -104,15 +104,6 @@ class AfterSetCookieSessionRoute(MeDaCaRoute): async def post_process_route(self, request: Request, response: Response): response = await super().post_process_route(request, response) - # X-Frame-Optionsヘッダー追加 - response.headers['X-Frame-Options'] = 'DENY' - # X-Content-Type-Optionsヘッダー追加 - response.headers['X-Content-Type-Options'] = 'nosniff' - # Strict-Transport-Securityヘッダー追加 - response.headers['Strict-Transport-Security'] = 'max-age=31536000 includeSubDomains' - # Cache-Controlヘッダー追加 - response.headers['Cache-Control'] = 'private' - session_key = response.headers.get('session_key', None) # セッションキーがない場合はセットせずに返す if session_key is None: From ff6dd0b68a6c6b68b50133c56854df036465274c Mon Sep 17 00:00:00 2001 From: "shimoda.m@nds-tyo.co.jp" Date: Mon, 29 Jan 2024 17:21:31 +0900 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20SRI=E3=83=8F=E3=83=83=E3=82=B7?= =?UTF-8?q?=E3=83=A5=E5=80=A4=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6=E8=A8=98?= =?UTF-8?q?=E8=BF=B0=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/README.md | 47 +++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/ecs/jskult-webapp/README.md b/ecs/jskult-webapp/README.md index e85ed943..5eda4c73 100644 --- a/ecs/jskult-webapp/README.md +++ b/ecs/jskult-webapp/README.md @@ -196,15 +196,38 @@ - リクエスト到達時にセッションの有無をチェックする - レスポンス時、クッキーにセッションキーを登録する -## ヘッダーにSRI設定・生成方法 -- インポートされたソースに更新したら、SRIのintegrity hashも更新すること - - ソースはローカルにある場合下記の`bash`コマンドでハッシュ生成できる: - ``` - cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A - ``` - - 外部ソース *(リンクから)* 使用する場合は下記のMDNオンラインツールでハッシュ生成できる: - [SRI Hash Generator](https://www.srihash.org/) - - SRIサンプル: - ``` - - ``` +## HTMLで読み込んでいるスクリプトのSRIハッシュ値を生成・設定する方法 + +### サブリソース完全性 (Subresource Integrity, SRI) とは + +CDN などから取得したリソースが意図せず改ざんされていないかをブラウザーが検証するセキュリティ機能です。 SRI を利用する際には、取得したリソースのハッシュ値と一致すべきハッシュ値を指定します。 + +詳細: + +実消化&アルトマークのWebアプリケーションでは、複数の外部スクリプトを読み込んで動作しているため、読み込むスクリプトを変更した場合は、 +タグの属性値`integrity`に設定されているスクリプトのハッシュ値を更新する必要がある。 + +### SRI ハッシュ値の生成方法(サーバー内のスクリプトについて) + +- サーバー内に保管されているスクリプトを更新した場合、Linux環境(WSL2でも可)で、以下のコマンドを実行し、ハッシュ値を生成する + +```bash +cat <更新したスクリプトファイル名> | openssl dgst -sha384 -binary | openssl base64 -A +``` + +参考: + + +### SRI ハッシュ値の生成方法(外部サイトから読み込んでいるスクリプトについて) + +- 外部サイトから読み込んでいるスクリプトを更新した場合、下記のMDNオンラインツールでハッシュ値を生成する + - [SRI Hash Generator](https://www.srihash.org/) + +### SRI ハッシュ値の設定方法 + +- 更新したスクリプトを読み込んでいる箇所の`integrity`属性値を、生成したハッシュ値に置き換える +- 以下は設定のサンプル + +```bash + +``` From 172c6e070b7a1a330cfdbb9911da7e04f41f6556 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Tue, 30 Jan 2024 09:21:04 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E3=82=A8?= =?UTF-8?q?=E3=83=A9=E3=83=BC=E3=83=8F=E3=83=B3=E3=83=89=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/main.py | 5 ++- .../src/middleware/middleware.py | 31 ------------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/ecs/jskult-webapp/src/main.py b/ecs/jskult-webapp/src/main.py index 61a8170f..f0e1807d 100644 --- a/ecs/jskult-webapp/src/main.py +++ b/ecs/jskult-webapp/src/main.py @@ -10,7 +10,7 @@ from src.controller import (bio, bio_api, healthcheck, login, logout, from src.core import task from src.error.exception_handler import http_exception_handler from src.error.exceptions import UnexpectedException -from src.middleware.middleware import ErrorHandlingMiddleware, SecurityHeadersMiddleware +from src.middleware.middleware import SecurityHeadersMiddleware app = FastAPI(openapi_url=None) @@ -43,8 +43,7 @@ app.add_exception_handler(status.HTTP_403_FORBIDDEN, http_exception_handler) # サーバーエラーが発生した場合のハンドラー。HTTPExceptionではハンドリングできないため、個別に設定 app.add_exception_handler(UnexpectedException, http_exception_handler) -# セキュリティヘッダー設定・サーバーエラーや認証失敗はミドルウェアで処理する -app.add_middleware(ErrorHandlingMiddleware) +# セキュリティヘッダー設定はミドルウェアで処理する app.add_middleware(SecurityHeadersMiddleware) # サーバー起動時のイベント diff --git a/ecs/jskult-webapp/src/middleware/middleware.py b/ecs/jskult-webapp/src/middleware/middleware.py index 64ffeb0b..264fd190 100644 --- a/ecs/jskult-webapp/src/middleware/middleware.py +++ b/ecs/jskult-webapp/src/middleware/middleware.py @@ -14,34 +14,3 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware): # Cache-Controlヘッダー追加 response.headers['Cache-Control'] = 'private' return response - -class ErrorHandlingMiddleware(BaseHTTPMiddleware): - # エラーハンドリングをするミドルウェア - # API内で発生したエラーをキャッチして処理を施す - - async def dispatch(self, request: Request, call_next) -> Response: - try: - response: Response = await call_next(request) - except TypeError as e: - response = JSONResponse( - {"msg": "TypeError:内容を確認してもう一度データ挿入をしてください。"}, - status.HTTP_404_NOT_FOUND, - ) - except TimeoutError as e: - response = JSONResponse( - {"msg": "TimeoutError:タイムアウトエラーが発生しました。"}, - status.HTTP_408_REQUEST_TIMEOUT, - ) - except RuntimeError as e: - response = JSONResponse( - {"msg": "RuntimeError:ランタイムエラーが発生しました。"}, - status.HTTP_500_INTERNAL_SERVER_ERROR, - ) - except Exception as e: - response = JSONResponse( - {"msg": "Exception:基底クラスエラーが発生しました。"}, - status.HTTP_500_INTERNAL_SERVER_ERROR, - ) - return response - - From c5d99acf1b0139dee023f2371a5a3490aa198b84 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Tue, 30 Jan 2024 09:29:14 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=AB=E3=83=80?= =?UTF-8?q?=E6=A7=8B=E6=88=90=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ecs/jskult-webapp/README.md b/ecs/jskult-webapp/README.md index 5eda4c73..c65cbf83 100644 --- a/ecs/jskult-webapp/README.md +++ b/ecs/jskult-webapp/README.md @@ -84,6 +84,8 @@ │   ├── exception_handler.py -- FastAPI内部でエラー発生時のハンドリング │   └── exceptions.py -- カスタム例外クラス ├── main.py -- APサーバーのエントリーポイント。ここでルーターやハンドラーの登録を行う + ├── middleware -- ミドルウェアの設定 + │ └── middleware.py ├── model -- モデル層(MVCのM) │   ├── db -- リポジトリから返されるDBレコードのモデル │   │   ├── base_db_model.py