■23/5/29 7:30PM
GCP hands-off 2
■プロジェクト削除時のサービスアカウントプロジェクトは30日保留される。その間サービスアカウント権限は生きており他プロジェクトでは動作する。しかし保留期間はプロジェクトを使用できずサービスアカウントを削除できず、個別に一つ一つ権限をはく奪するしかない。
サービスアカウントはプロジェクト削除前に、必要であれば事前に削除や無効化しておくことも検討する。
■連携
GoogleWorkspace -> GAS -> GCP Oauth + API -> GCP(Bigquery etc.)Python -> Gcloud sdk -> gcloud auth -> GCP(Bigquery etc.) <-> federation query/Connected sheet
Python(Oauth key) -> GCP認証情報(Oauth Key) + API -> GoogleWorkspace
GCPのクレデンシャルページでOauth2.0 client IDと鍵が発行でき、鍵でイケる
Pythonコードで鍵を指定すると実行時にログインを求められ、client IDとユーザIDを紐づけして実行することになる Authentication — gspread 5.7.2 documentation
Python でシンプルに OAuth 2 する (urllib + oauthlib) - Qiita
GCPのクレデンシャルページでAPIキーも発行でき、これは可能性はあるPython -> local csv/tsvが基本
●Python(SA key) -> GCP認証情報(SA Key) + API -> GoogleWorkspace
サービスアカウントでGWSにアクセスできないのでダメ
信頼しているドメインとのみ外部共有を許可する - Google Workspace 管理者 ヘルプ
サービス アカウント(ドメイン名の末尾が「gserviceaccount.com」)を信頼しているドメインにすることはできません
OUで許可するとイケるはずだが、、
●Python でGoogle docをイジるGoogle Docs APIを使って文章を作成してみる - より良いエンジニアを目指して (hatenablog.com)Google Docs APIを使って、索引を作成する #Python - Qiitaスコープ情報 Google API の OAuth 2.0 スコープ | Authorization | Google for Developers下記のURLの内容を検証すればよいPython のクイックスタート | Google Docs | Google for DevelopersGoogle CloudコンソールでOauth同意画面を設定Google Docs APIを有効化OAuth クライアントIDを作成シークレットJson ファイルができるのでDL(リネーム)コードにクレデンシャルJSONファイルとDocのURLに含まれるdocumentIDを記述→Python実行するとDocのデータが取れる(ローカルの場合は楽)
/// runのデプロイ時に設定を入れる方法について1)環境変数を(コンソール/cmd/コンテナymiのどれかで)設定:env=os environ.get("ENV") で使う。ログに出やすく非推奨2)シークレットマネージャ保存分を設定環境変数+コードでやるのと同じ?3)ボリュームを使う:クレデンを入れ、トークンの一時保存ができる?Cloud RunでSecret Managerを使いたい #Python - Qiita
※サービスアカウントでGWSを扱うにはGWSのOUで受け入れる設定が必要な場合がある
■secret managerに保存してコードで呼び出して使う Secret Managerのシークレットアクセサー権限 シークレット バージョンにアクセス | Secret Manager Documentation | Google Cloud (checksumをかけている)
from google.cloud import secretmanagerimport google.cloud.loggingimport loggingdef get_url(secret_key, project_num) logging.warning('####### secret_key' + str(secret_key) + '######') client = secretmanager.SecretManagerServiceClient() resource_name = "projects/()/secrets/()/versions/latest.format(project_num, secret_key) res = client.access_secret_version(resource_name) slack_url = res.payload.data.decode("utf-8") return slack_url
■API等でデータを取った時中身が分からない場合pramsが何かわからん時print(params)print(type(params))#<class 'proto.marshal.collections.maps.MapComposite'>#よくわからんクラスでもdirで保持するAttributeが分かるattributes = dir(params)print(attributes)#そこに含まれるメソッドも確認できるのでhelpするhelp(params.get) #prams.get('query')すると含まれるSQLが分かりこれで進める等
■Protocol buffersAPIの返りはGoogleは自社で開発したProtocol buffersを使っていようだたとえば下記が返るname: "projects/98765"parent: "folders/12345"project_id: "aaaaaa-bbbb-market"state: "ACTIVE"display_name: "aaaaaa-bbbb-market"create_time{ seconds: 1601250933 nanos: 820000000}update_time{ seconds: 1632826231 nanos: 634000000}etag: "W/a06910d9093db111"labels{ key: "budget_group" value: "cccc"}
これはprint (type(response))すると下記であり<class "google.cloud. resourcemanager v3.types.projects.Project"> print (response.project_id) で簡単にデコードし値取得できることが分かる
APIからの値を取るときのコードfrom google.cloud import resourcemanager_v3client = resourcemanager_v3.ProjectsClient()request resourcemanager v3.ListProjectsRequest{ #組織の場合、現状は権限がGOP側で用意がなく無理だった #parent organizations/12345678. parent="folders/1122233344"}page_result = client.list_projects(request=request)for response in page result: print(type(response)) print (response.project_id)
エンコードする場合 https://blog.imind.jp/entry/2019/12/28/124728pip install googleapis-common-protos でインスコ?sudo apt install protobuf-compiler でインスコ
sudo apt-get install protobuf-compiler でインスコ ※google提供のフォルダごと使用しようとして失敗した方法 ※googleapis/google/cloud/resourcemanager/v3/projects.proto at master · googleapis/googleapis · GitHub ※にprotoファイルがあるが丸々必要なので下記でDL ※git clone https://github.com/googleapis/googleapis.git ※バスを合わせてprojects.protoを使うが失敗 ※たとえば protoc python_out=. --proto_path=googleapis ./googleapis/google/cloud/resourcemanager/v3/projects.protoprojects.proto を下記の内容で一から作成することが必要だったsyntax proto3;
message Resource{ string name = 1; string parent = 2; string project_id = 3; string state = 4; string display_name = 5; map<string, string> create_time = 6; map<string, string> update_time = 7; string etag = 8; map<string, string> labels = 9;}そして下記を実行しコンパイルprotoc --python_out=. ./projects.protoprojects_pb2.pyが生成されるため、パッケージとして読みこみprotocol buffersを実行できるようになるimport projects_pb2.py※なおエラーで pip install U protobuf=3.20.0でダウングレードした
注意点としては、pythonとprotocol bufferとBigqueryの型合わせが必要 DateやTimestampはUNIXエポックからの日数や秒数に変換する必要がある Noneをstr 'None'や、int -1や、bool FalseにPythonで調整をするBigQuery Storage Write API を使用してデータを一括読み込み、ストリーミングする | Google Cloud
//UNIXエポックからの日数current_date = datetime.now()epoch = datetime(1970, 1, 1)record_date = (current_date - epoch).days
//UNIXエポックからの秒数data_string = str(date_v)dt_obj = datetime.fromisoformat(date_string.replace("Z","+00:00"))epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)seconds_since_epoch = (dt_obj - epoch).tatal_seconds()microseconds_since_epoch = int(seconds_since_epoch * 1e6)date_v = microseconds_since_epoch
■BQ APIクォータ割り当て超過(1000件insertしようとした)割り当てと上限 | BigQuery | Google Cloudテーブル変更1日1500件までテーブルメタデータ変更は10sあたり5回までテーブル当たりDMLの実行待ちキューは20件までテーブル当たり10sあたり25のDMLまで→各insertでスリープを5秒入れた import time time.sleep(5)
↓
上限がテーブル単位のためテーブル名を分けると回避できるらしいGCP BigQuery 応用編 ~制限について~ - 自称フルスタックエンジニアのぶろぐ。 (hatenablog.com)
↓■BQ streaming insert->BQ storage read/write APIの上限はDMLと別で、閾値が大きい
streaming insert -> Bigquery storage write API を使うINFORMATION_SCHEMAを用いたBigQueryのストレージ無駄遣い調査 - ZOZO TECH BLOGBigQuery Storage Write API を使用してデータを一括読み込み、ストリーミングする | Google Cloud
Storage Write API を使用したデータ読み込みのバッチ処理 | BigQuery | Google Cloud
CreateWriteStream > AppendRows(ループ) > FinalizeWriteStream > BatchCommitWriteStreams
をstart/append/send/close(write commit)の関数化し返り値でつなげた形にしたが sendをした後 proto_rows = types.ProtoRows() を掛け初期化する必要があった(offsetが倍々で増えたから)offsetで送信毎の開始行の設定も必要(一連の処理で件数を記憶しており0固定で処理を書けないようだった)
■Python/Client libraryの値をBQに入れるにあたり仕様書で型を調べる。STRUCTやクラスは紐解いて通常のカラムでBQに挿入timestampやboolやint64はそのままの形でBQに挿入BQ SQL:日付は値なしならNULLを入れる、数値やBool値はクォートで囲まないPythonでSQLインサート文を作るとき改行コードが含まれるものをセットするとSyntax errror:Unclosed string literalq = q.replace('//', '////') バックスラッシュをエスケープ、あるとイリーガルエスケープシーケンスとなる、raw文字列にしたい?
q = q.replace('/n', '//n') 改行をエスケープq = q.replace("'", "\\'") SQLが途切れないようシングルクォートをエスケープq = q.replace('/n', ' ') 改行を空白で置き換える
■変更の判断
変更で問題がでないか→PCにマウスと付けて問題が起こらないかという問題と相似、最終的に経験で判断するしか
■監査ログからSetIamのメソッドを取りBQ権限付与を検知するクエリ
WITH source AS(SELECT*FROM `project-logging.organization_audit_log_v2.cloudaudit_googleapis_com_activity_20*`WHERE_TABLE_SUFFIX = format_date('%y%m%d', current_date("Asia/Tokyo"))),project source AS(SELECTROW_NUMBER() OVER (ORDER BY timestamp) as id,*FROM sourceWHEREprotopayload_auditlog.methodName = 'SetlamPolicy'project_authorizationinfo AS(SELECTDISTINCTid,__ori.resource.type as type,__ori.resource.labels.project_id as project_id,__ori.resource.labels.dataset_id as dataset_id,protopayload_auditlog.methodName as method_nameprotopayload_auditlog.resourceName as resource_name,protopayload_auditlog.authenticationInfo.principal Email as email_manipulator,authorizationInfo.resource as request_resource,authorizationInfo.permission as request_permission,authorizationInfo.granted as request_granted,protopayload_auditlog.requestMetadata.callerlp as callerlp,protopayload_auditlog.requestMetadata.callerSuppliedUserAgent as callerSuppliedUserAgent,FROM project_source AS __ori). UNNEST (protopayload_auditlog.authorizationInfo) AS authorizationInfoproject_bindingdeltas AS(SELECTid,--array_binding Deltas_project as binding Deltas_project,array_binding Deltas_project.action as action_project,array_binding Deltas_project.member as member_project,array_binding Deltas_project.role as role_project,timestampFROM project_source AS_ori,UNNEST (protopayload_auditlog.servicedata_v1_iam.policyDelta.bindingDeltas) AS array_binding Deltas_project),project_setiam AS(SELECT--*, except(id)type,project_id,dataset_id,method_name,resource_name,email_manipulator,request_resource,request_permission,request_granted,callerip,callerSuppliedUserAgent.action_project,member_project,role project.CAST(NULL AS STRING) AS metadataJson,CAST(NULL AS STRING) AS bindingDeltas_dataset,CASTINULLAS STRING AS action_dataset,CAST(NULL AS STRING) AS member_dataset,CAST(NULL AS STRING) AS role_dataset,CAST(NULL AS STRING) AS bindingDeltas_table,CAST(NULL AS STRING) AS action_table,CAST(NULL AS STRING) AS member_table,CAST(NULL AS STRING) AS role_table,timestampFROM project_authorizationinfoLEFT JOIN project_bindingdeltas ON project_authorizationinfo.id = project_bindingdeltas.idWHERE role_project LIKE 'roles/bigquery%),resource_source AS (SELECT__ori.resource.type as type,__ori.resource.labels.project_id as project id,__ori.resource.labels.dataset_id as dataset_id,protopayload_auditlog.methodName as method_name,protopayload_auditlog.resourceName as resource_name,protopayload_auditlog.authenticationInfo.principalEmail as email_manipulator,authorizationInfo.resource as request_resource,authorizationInfo.permission as request_permission,authorizationInfo.granted as request_granted,protopayload_auditlog.requestMetadata.callerlp as callerlp,protopayload_auditlog.requestMetadata.callerSuppliedUserAgent as callerSuppliedUserAgent,protopayload_auditiog.metadataJson,timestampFROM source AS __ori,UNNEST(protopayload_auditlog.authorizationInfo) AS authorizationInfo WHEREprotopayload_auditlog.methodName = 'google.iam.v1.IAMPolicy.SetlamPolicy' --AND timestamp= "2024-03-11 04:11:30.885258 UTC"),resource_id AS (SELECTROW_NUMBER() OVER (ORDER BY timestamp) as id,*FROM resource_source),resource_bq_dataset AS (SELECTid as id_dataset,json_extract(metadataJson, '$.datasetChange bindingDeltas') as bindingDeltas_dataset,json_extract(array_bindingDeltas_dataset, '$action') as action_dataset,json_extract(array_bindingDeltas_dataset, $.member') as member_dataset,json_extract(array_bindingDeltas_dataset, '$.role') as role_dataset,FROM resource_id,UNNEST(json query_array(metadataJson, '$.datasetChange.bindingDeltas')) AS array_bindingDeltas_dataset),resource_bq_table AS (SELECTid as id table,json_extract(metadataJson, '$.tableChange.bindingDeltas') as bindingDeltas_table,json extract(array_bindingDeltas_table, '$.action') as action table,json_extract(array_bindingDeltas_table. '$.member') as member table,json_extract(array_bindingDeltas_table, '$.role') as role_table,FROM resource_id,UNNEST(json query_array(metadataJson, '$.tableChange.bindingDeltas')) AS array_bindingDeltas_table),resource_setiam AS ( SELECT--*except(id, id_dataset, id_table)type,project_id,dataset_id,method_name,resource_name,email_manipulator,request_resource,request_permission,request_granted,callerlp,callerSuppliedUserAgent,CAST(NULL AS STRING) AS action_project,CAST(NULL AS STRING) AS member_project,CAST(NULL AS STRING) AS role_project,metadataJson,bindingDeltas_dataset,action_dataset,member_dataset,role_dataset,bindingDeltas_table,action_table,member_table,role_table,timestampFROM resource_idLEFT JOIN resource_bq_dataset ON resource_id.id = resource_bq_dataset.id_datasetLEFT JOIN resource_bq_table ON resource_id.id = resource_bq_table.id_table)SELECT * FROM project_setiamUNION ALLSELECT * FROM resource_setiam
■BQからCloudSQLにデータを入れる (GCSを経由する、コマンドやPythonがあるbq query --use_legacy_sql=false 'CREATE OR REPLACE TABLE `prj.ds._table` AS SELECT FROM `prj.ds.view`';bq extract -destination_format CSV 'prj.ds._table' gs://bucket/tbl.csvgcloud sql import csv インスタンス名 gs://bucket/tbl.csv --database=データベース名 --table=テーブル名
■ログの重複をなくす
import google.cloud.loggingimport logging
# クライアントの作成client = google.cloud.logging.Client()
# Cloud Logging ハンドラを追加client.get_default_handler()client.setup_logging()
# 既存のハンドラをすべて削除for handler in logging.root.handlers[:]: logging.root.removeHandler(handler)
# 新しいハンドラを追加logging.basicConfig(level=logging.INFO)
# logging.basicConfig(level=logging.DEBUG) # DEBUG レベルからすべてのレベルを記録
# propagate を無効にして重複を防ぐlogger = logging.getLogger()logger.propagate = False
# 各ログレベルでテストlogging.debug('This is a DEBUG log')logging.info('This is an INFO log')logging.warning('This is a WARNING log')logging.error('This is an ERROR log')logging.critical('This is a CRITICAL log')
■何度かAPIコールを繰り返す
def safe_replace_text(document_id, old_text, new_text, max_attempts=3): for attempt in range(max_attempts): try: replace_text(document_id, old_text, new_text) break # 成功した場合はループを抜ける except Exception as e: print(f"Attempt {attempt + 1} failed: {e}") if attempt == max_attempts - 1: print("Reached maximum attempts.")
■Exponential Backoffで時間を指数級数的にゆらぎながら増やすリトライimport timeimport randomdef exponential_backoff(max_retries=5, base_wait_time=1, max_wait_time=32): retries = 0 while retries < max_retries: try: # APIリクエストの送信 response = send_request() if response.status_code == 200: return response # 成功時に結果を返す except Exception as e: wait_time = min(base_wait_time * (2 ** retries), max_wait_time) wait_time += random.uniform(0, 1) # ランダムなズレを追加(Jitter) print(f"Retrying in {wait_time} seconds...") time.sleep(wait_time) retries += 1 raise Exception("Max retries reached, request failed")
クォータの増加の依頼もできるが、基本的に下記の上限がある
1. Google Docs API の利用上限- ユーザーごとの1分あたりのリクエスト数:
- プロジェクトごとの1日あたりのリクエスト数:
- プロジェクトごとに1日100万リクエスト(デフォルト)
これらの制限を超えると、リクエストが拒否されるか、APIを利用できなくなることがあります。
2. Google Drive API の利用上限- ユーザーごとの100秒あたりのリクエスト数:
- プロジェクトごとの1日あたりのリクエスト数:
- ユーザーごとのデータ転送量の制限:
- 読み込みは750GB/日/ユーザー
- 書き込みはユーザーごとの制限が異なるため、大量のデータ処理を行う場合は注意が必要
Comment (0)
■23/2/11 1:46AM
HSTS/CORS/CSPOAuth/OpenID/SAML/XSS/CSRF/JSOP/SSO/SSL/SVG/JWT/WebAssembly
2024-10-6
クレカ情報の流出があったタリーズオンラインストアのWebアーカイブから原因を特定した猛者が現れる→集まった有識者たちにより巧妙な手口が明らかに - Togetter [トゥギャッター]
レスポンスヘッダーに Content-Security-Policy が適切に設定されていれば防げた可能性は高い。具体的には▼ connect-src ディレクティブの設定スクリプトからの外部リソースへの通信先を制限して、マルウェアが悪意あるドメインにデータを送信するを防ぐ。例. Content-Security-Policy: connect-src 'self' https://api.trustedservice.com;▼ eval() の禁止Content-Security-Policy はデフォルトで eval() の使用を禁止しているが、 'unsafe-eval' を指定することで許可できる。
slick.jsのライブラリに仕込まれていたので、管理者がやったんじゃないの?slickスライダー実装まとめ16選【サンプル付き】 - じゅんぺいブログ (junpei-sugiyama.com)
2024-7-5
Webサービス公開前のチェックリスト (zenn.dev)
2023-02-11
フロントエンド開発のためのセキュリティ入門 - Speaker Deck
HTTPとHTTPSが混ざっているwebサイトはHSTS(http strict transport securityヘッダ)でHTTPS強制できる JSのfetch,xhr/iframe/canvas/WebStorage,IndexedDBでクロスオリジンは危険 Access-Control-Allow-OriginレスポンスヘッダでCORS(cross origin resource sharing)許可を判定できる CSP(Content-Security-Policy)レスポンスヘッダあるはmetaタグで許可するJSを判定できる
SVG
SVG Repo - Free SVG Vectors and Icons
Vector Icons and Stickers - PNG, SVG, EPS, PSD and CSS (flaticon.com)
SVGはテキストファイルなので開いてタグとして使える
ChatGPTにSVGでお絵描きさせる|temoki / Tomoki Kobayashi (note.com)
タグで図が書ける
SVGファイルについて (zenn.dev)
sizeを決めてviewBoxの座標を設定するのがやりやすい
JWT (JSON WEB TOKEN?)
JWTセキュリティ入門 - Speaker Deck
WebAssemblyとは?〜実際にC言語をブラウザで動かす〜【2019年6月版】 #JavaScript - Qiita
コンパイルしてバイナリをWebで実行する、速いJSみたいな、ゲームやエミュやCアプリ的な奴
=========================
2022-04-06
SAML SSOのログイン状態を保持する認証プロバイダー(IdP)を使い各アプリ(ServiceProvider)でSSOを実現する SSOの仕組みにはエージェント方式、リバースプロキシ方式、代理認証方式など ユーザはWebサービスにアクセス WebサービスからSSO認証プロバイダーサーバにSAML認証要求をPostする SSO認証プロバイダーサーバでSAML認証を解析、ユーザに認証を転送 ユーザはそれでWebサービスにログインする
SAMLはログイン時にユーザー情報をチェック、OAuthはユーザーの情報を登録OAuthはアプリケーションを連動させるAPIで有効なアクセストークンかを見る アクセストークンには「いつ」「どこで」「なんのために」作られたのか分からないOpenIDはIDトークンを使い「いつ」「どこで」「なんのために」作られたのか分かる
OAuth 2.0、OpenID Connect、SAMLを比較OAuth 2.0:新しいアプリケーションに登録して、新しい連絡先をFacebookや携帯電話の連絡先から自動的に取得することに同意した場合は、おそらくOAuth 2.0が使われています。この標準は、安全な委任アクセスを提供します。つまり、ユーザーが認証情報を共有しなくても、アプリケーションがユーザーに代わってアクションを起こしたり、サーバーからリソースにアクセスしたりすることができます。これは、アイデンティティプロバイダー(IdP)がユーザーの承認を得て、サードパーティのアプリケーションにトークンを発行できるようにすることで実現されます。
OpenID Connect:Googleを使ってYouTubeなどのアプリケーションにサインインしたり、Facebookを使ってオンラインショッピングのカートにログインしたりする場合に使用されるのが、この認証オプションです。OpenID Connectは、組織がユーザーを認証するために使用するオープンスタンダードです。IdPはこれを利用して、ユーザーがIdPにサインインした後、他のWebサイトやアプリにアクセスする際に、ログインしたりサインイン情報を共有したりする必要がないようにします。
SAML:SAML認証は、多くの場合に仕事環境で使用されます。たとえば、企業のイントラネットやIdPにログインした後、Salesforce、Box、Workdayなどの多数の追加サービスに、認証情報を再入力せずにアクセスできるようになります。SAMLは、IdPとサービスプロバイダーの間で認証・認可データを交換するためのXMLベースの標準で、ユーザーのアイデンティティとアクセス許可を検証し、サービスへのアクセスの許可/拒否を決定します。OAuth、OpenID Connect、SAMLの違いとは? | Okta
Oath: idpがトークンを発行、Webサイト間でユーザを認識し3rdからでも個人情報を使えるようになるOpenID(OIDC): idpとJWT(トークン)で認証するOauth系のSSO、Oauthの拡張でログインが3rdからもできるようになるSAML: idpで各アプリやAD間をXMLメッセージにより認証管理しSSOを実現 OpenIDとSAMLが同じような機能 SAMLはユーザ固有の傾向で大企業SSOが多い、OpenIDはアプリ固有の傾向でWebサイトやモバイルアプリが多い SAMLよりOIDCの方が新しくSPAやスマホと親和性が高い SaaSとしてOpenIDはOktaのidp、SAMLはPingFederateのidpがメジャー
=========================
2016-01-03
■XSS対策、CSRF対策、脆弱性チェック
情報処理推進機構にチェックリスト有
https://www.ipa.go.jp/security/vuln/websecurity.htmlXSS対策
フォーム送信後の確認画面ではHTMLエスケープ等でサニタイズされた内容の結果を表示
DBへのクエリについてはプレースホルダやエスケープ等でSQLインジェクションを防ぐ
target="_blank"はXSSになるので危ない、rel="noopener noreferrer"を付ける
https://b.hatena.ne.jp/entry/s/webtan.impress.co.jp/e/2020/03/13/35510
https://laboradian.com/test-window-opener/
CSRF対策
前ページでhidden値を入れる
他
クッキーに具体的なものは入れない、CookieにHttpOnly属性、HTTPS通信ではsecure属性
エラーメッセージを表示しない
不要なファイルは削除
XMLの外部実態参照は禁止、サーバ上でコードが実行される
→libxml_disable_entity_loader(true)で止める、xmlをアップロードさせない/使用しない、JSON使う
PDFからHTTPリクエストが発行される
→PDFをアップロードさせない
------
//SQLインジェクション対策
$sql = "UPDATE users SET name='.mysql_real_escape_string($name).'WHERE id='.mysql_real_escape_string ($id).'";
\ " ' を最低限、\エスケープNUL (ASCII 0) /n /r / ' " およびCTRL+Zをエスケープしたい
//クロスサイトスクリプティング対策
表示時には<>&"をメタ文字へ変換
echo htmlspecialchars($_GET['username'], ENT_QUOTES);
$ent = htmlentities($ent, ENT_QUOTES, "UTF-8"); //100個の文字を変換
//クロスサイトスクリプティング対策
別サイトからのポストを弾く
refferを送信しないリクエストもある(別サイトのリファラを弾き、nullもしくは適切ページからを許可する)
セッションIDで判断する
//DOS対策
2重ポスト
IPと日付で2重ポストを防ぐ(同IPのポストがx秒以内を弾く)
■サニタイズの方法DOCには生のテキスト、DBとHTMLにはエスケープ済みのものを入れる• 入力があればhtmlエスケープしDBに入れる• html表示はそのままhtmlエスケープ状態で出力• Docへはhtmlエスケープを解除し表示• htmlフォーム内表示はhtmlエスケープを解除し表示htmlエスケープhttps://weblan3.com/html/special-characterバッククォート以外は分かり易いで文字表記でエスケープする、改行はエスケープしない< < < 不等号(より小さい)> > > 不等号(より大きい)& & & アンパサンド" " " 二重引用符' ' ' シングルクォート,アポストロフィ; ;: ; セミコロン\ \ &bsol バックスラッシュ` ` バッククォート
========
■JSONP
scriptタグを使用してクロスドメインなデータを取得する仕組みのことである。
HTMLのscriptタグ、JavaScript(関数)、JSONを組み合わせて実現される
GoogleAnalyticsのクッキーは1stパーティでサイト側がオーナでありGoogleがオーナーではない
サイト側のJSでクッキーが作成されるようなっている
クッキーが送信される相手はどこか?が重要でGoogleでなくサイト側に送信される
アクセス履歴は別途データをGoogleに送信しており、クッキーはセッション管理に使用される
■SSO
色々な方法がある、SAMLや、サイトにエージェントを組み込み+SSO認証サーバ等
ロジックを確認しないと詳しくは分からない
=========
■SSL【図解】よく分かるデジタル証明書(SSL証明書)の仕組み 〜https通信フロー,発行手順,CSR,自己署名(オレオレ)証明書,ルート証明書,中間証明書の必要性や扱いについて〜 | SEの道標 (nesuke.com)デジタル証明書の仕組み (infraexpert.com)
認証局とは | GMOグローバルサインカレッジ (globalsign.com)
サーバでRSA秘密鍵とCSRを生成し公開鍵を認証局(CA)登録CAはサーバに証明書(署名)を発行====クライアントが接続要求サーバが証明書(署名とRSA公開鍵を含む)を送るクライアントが証明書を検証(
どっち?
1)署名をルート証明書のチェーン(RSA公開鍵)で複合化しドメインを確認
該当のルート証明書(RSA公開鍵)がブラウザにないと該当CAに要求?
CRLやOCSPで失効について問合せができるようだがRSA公開鍵の要求は出来なさそう (ルート証明書はブラウザにある結局オレオレ証明書に違いない:厳密な審査の上で組込まれている)
2)クライアントが公開鍵をサーバに送りRSA秘密鍵で暗号化し送り返すとクライアントが複合化してRSA秘密鍵が正しい事を確認
)クライアントが共通鍵(セッションキー)を生成し公開鍵で暗号化し送るサーバが秘密鍵で共通鍵を複合
以降共通鍵暗号で通信 ※ホンマか??
====
ホスト(ドメイン)を持って接続要求をし、暗号化通信後にパスやクエリパラメータを送るので、詳細は暗号化され守られている
Comment (0)
■22/7/24 3:46AM
Docker
どこでビルドしてもデプロイしてもImmutableインフラ(不変の)なので変更したい場合はDockerfileの方を変えるコンテナはOS上のDockerEngine上に配置する(コンテナは複数配置できる、Dockerfileさえあれば再現可)
DockerfileでなくてもDockerイメージでもいいが、Dockerは可搬性をもたらすのである なおVMはOSをもシミュレート
1部: はじめに|実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本 (zenn.dev)
2部: Dockerfile の基礎|実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本 (zenn.dev)
3部: Docker Compose|実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本 (zenn.dev)
Dockerのチュートリアル - とほほのWWW入門 (tohoho-web.com)
Dockerコマンド - とほほのWWW入門 (tohoho-web.com)
コンテナ設計方針をまとめてみた - Qiita
社内のDockerfileのベストプラクティスを公開します│FORCIA CUBE│フォルシア株式会社
Docker完全に理解した | IIJ Engineers Blog
ボリュームマウント=DockerEngine上にボリュームを作りコンテナにマウント(操作が面倒で仮使用や永続ファイル用)
バインドマウント=LinuxOS上のファイルやディレクトリをマウント(ファイル編集が多い場合)
dockerfile(イメージを作る)、docker compose(yamlで一括でコンテナ/nw/volを作る)
dockerfile: dockerイメージを作る→runでコンテナ(アプリ)になる
docker composer: コンテナを作る、NWやボリュームも作る→1台にまとめる
マニフェスト: k8sを作る→複数台になる
Dockerfileによるビルド - とほほのWWW入門 (tohoho-web.com)
Docker Compose - とほほのWWW入門 (tohoho-web.com)
■Dockerインスコ
/// BANGBOO BLOG /// - GCP script ここの下の方に記載あり
docker --versionwho 誰がログインしているかsudo gpasswd -a [ユーザ名] docker dockerグループへ追加?
■Docker Engine起動
sudo systemctl start docker これ要る?
■オプション
-i キーボードを繋ぐ
-t 特殊キーを使用可能にする
-e 環境変数名=値(複数記載可能)
--net=ネットワーク名
-v ${pwd}:/app はOSローカル環境とコンテナ内のディレクトリを同期-p, -public 80:8000 ポートの紐づけ-d, -detach バックグラウンド実行(デタッチ)-rm コンテナ実行後にコンテナを自動削除する(イメージは残る)
-dit とまとめられる
■操作コマンド
docker images リストdocker tag [イメージID] img_unco:latest 名前がつかない場合docker rmi [イメージID] 削除docker ps -a コンテナ一覧
docker container ls コンテナのステータス確認docker rm [コンテナID] 削除
■起動
httpd3つを1つのイメージで建てられる(以前はdocker runだった)docker container run --name コンテナ名001 -d -p 8081:80 イメージ名httpd
docker container run --name コンテナ名002 -d -p 8082:80 イメージ名httpddocker container run --name コンテナ名003 -d -p 8083:80 イメージ名httpd
■仮想NW
コンテナ間をつなぐ(ネットワークタグ名で紐づける感じ)
1)ブリッジネットワーク(デフォルト 同一の Docker Engine 上のコンテナ が互いに通信をする場合に利用する デフォルト: 全てのコンテナ間をリンクする操作が必要 コンテナ間の通信は IP アドレスで ●(コレ使う)ブリッジネットワークを定義し作成: 相互通信は同じネットワークを割り当てるだけ コンテナ間でDNS解決される ネットワークでコンテナは隔離され隔離度が上がる2)オーバーレイネットワーク 異なる Docker Engine 上のコンテナ が互いに通信をする場合に利用
docker network create ネットワーク名net001
↓
docker container run --name mysql001 -dit --net=net001 ~~~ イメージ名mysql
docker container run --name wordpress001 -dit --net=net001 -p 8085:80 -e WORDPRESS_DB_HOST=mysql001 ~~~ イメージ名wordpress
Docker仮想NW一覧docker network ls仮想NWの確認docker network inspect net001
コンテナ間はservice_nemeで通信し、コンテナ名ではないhttp://unco-sv:8000 で通信できる各コンテナで同番ポートを使っていても問題はないdocker info プロキシ等が確認できる.docker/config.json でプロキシやプロキシを使わないnoProxyを設定
■停止
docker stop コンテナ名
docker rm コンテナ名
docker network rm ネットワーク名
■コピー OS⇔コンテナ
docker cp コピー元 コピー先
例)docker cp /home/a.txt コンテナ名:/app/
■ボリュームのマウント
データをコンテナ内に置くとコンテナが消えるとデータも消えてしまう
永続化1)ボリュームマウント:DockerEngine上
永続化2)バインドマウント:OS上
永続化3)一時メモリマウント:(tmpfs)
■バインドマウント
docker volume create ボリューム名vol001
docker run --name コンテナ名httpd001 -d -p 8080:80 -v /home/a:/usr/local/apache/htdocs イメージ名httpd (OS側パス:コンテナ側パス、コンテナ側のパスをどこにすべきかはDockerイメージのドキュメントを見よ)
docker volume inspect vol001 (確認できる)
docker volume rm vol001
ホストディレクトリ共有ともいう
コンテナはrootで動作しているものが多くホスト共有しているDir/Fileにコンテナから変更するとrootで変更しPermissionが変わるそのためホストディレクトリ共有は本番に向かない
■ボリュームマウント
ちょい面倒らしいのでバインドマウントでいいのでは?
docker volume create ボリューム名vol001
docker run --name コンテナ名httpd001 -d -p 8080:80 -v ボリューム名vol001:/usr/local/apache/htdocs イメージ名httpd (OS側パス:コンテナ側パス)docker volume inspect vol001 (確認できる)
docker volume rm vol001
Dockerボリューム共有ともいう
コンテナが削除されても明示的に消さない限り保持される永続化したいパスを指定してマウントできる(通常コンテナ内で作成されたデータは永続化しない)
■揮発的データを退避docker cp コンテナ名:ファイルパス ホスト側退避パス docker cp test-db-a:/opt/test.txt /tmp/config消えるファイルをホスト側に退避したいときのコマンド
■ボリュームマウントの確認やOS側にバックアップ
アプリコンテナとは別のshellコンテナを用意してlsしたりtar.gz等する
Apacheコンテナ <-> vol001 <- Linuxコンテナ -> vol002バックアップ
マウントを2つ(DockerEngine上のマウント、OS上のマウント)
tar.gzコピーでDockerEngine上の指定フォルダにコピーするが其れはOS側にもマウントされている、最後のドットも要る
イメージは軽量Linuxのbusyboxを使用
docker run --rm -v vol001:/usr/local/apache/htdocs -v /home/b:/tmp busybox tar CXvf /tmp/bjk.tar.gz -C /usr/local/apache/htdocs .
■ログdocker logs コンテナ名docker logs -f コンテナ名 追従確認docker exec -t コンテナ名 /bin/bash ログファイル等はこれで入り確認
■Appコンテナ(PHP)
docker container run \ --name app \ コンテナにappと名付る --rm \ コンテナ停止時に自動削除 --detach \ バックグラウド実行 --interactive \ 対話可能なセッションに --tty \ コンテナとのTTY接続しコマンド出力可 --mount type=bind,src=$(pwd)/src,dst=/src \ osにバインドマウント --publish 18000:8000 \ ポートマッピング
--network docker-sample-network \ 仮想NWに割り当て docker-php:app \ Dockerイメージの名前とタグ php -S 0.0.0.0:8000 -t /src コンテナ内で実行するコマンド
※永続化バインドマウントos上ホストマシンのディレクトリをコンテナ内のディレクトリにバインドマウント。ホストマシンのカレントディレクトリ($(pwd))の"src"ディレクトリが、コンテナ内の"/src"ディレクトリにマウントされます
※ポートマッピング-p, --publishがコンテナのポートをホストマシンに公開するオプションホストマシンの18000ポートを通じてコンテナの8000ポートにアクセスさせるブラウザからhttp://localhost:18000 でphpにアクセス
※起動コマンドPHPのビルトインウェブサーバを起動し、IPアドレス "0.0.0.0" およびポート "8000" でリクエストを受け付け、コンテンツを"/src"ディレクトリから提供します
■コンテナの詳細情報の確認
docker container inspect app
■DBコンテナ(MySQL)
docker container run \ --name db \ --rm \ --detach \ --platform linux/amd64 \ --env MYSQL_ROOT_PASSWORD=rootpassword \ --env MYSQL_USER=hoge \ --env MYSQL_PASSWORD=password \ --env MYSQL_DATABASE=event \ --mount type=volume,src=docker-db-volume,dst=/var/lib/mysql \ --mount type=bind,src=$(pwd)/docker/db/init.sql,dst=/docker-entrypoint-initdb.d/init.sql \ --network docker-sample-network \ --network-alias db \ docker-db:db
※仮想NWでのエイリアス名dbと名付ける
■コンテナの疎通の確認$ docker container exec --interactive --tty app ping db -c 3appコンテナがdbに疎通できるかping
■アプリ
/// BANGBOO BLOG /// - GCP script 下の方に記載あり
■Dockerfile
ビルドしてイメージを作成
FROM イメージ名
COPY コピー元パス コピー先パス
RUN Linuxのコマンド
ENTRYPOINT イメージを実行するときのコマンド
CMD コンテナ起動時に実行する規定のコマンドを指定
例えばこのコマンドを実行するCMDは $ go run /echo/main.go ↓空白で分割し配列化しCMD化される CMD["go", "run", "/echo/main.go"]
ただCMDは下記のように実行中に上書き指定ができ echo yayの実行となる
docker container run $(docker image build -q .) echo yayONBUILD ビルドが完了したときに任意の命令を実行する
EXPOSE 通信を想定するポートをイメージの利用者に伝える
VOLUME 永続データが保存される場所をイメージ利用者に伝える
ENV 環境変数を定義するWORKDIR RUN/CMD/ENTRYPOINT/ADD/COPYの際の作業ディレクトリSHELL ビルド時のシェルを指定
LABEL 名前やバージョンや制作者情報等を設定
USER RUN/CMD/ENTRYPOINT実行するユーザやグループを設定ARG docker buildする際に指定できる引数を宣言
STOPSIGNAL docker stopの際にコンテナで実行しているプログラムに対して送信するシグナルを変更する
HEALTHCHECK コンテナの死活確認をするヘルスチェックをカスタマイズする
Dockerセキュリティベストプラクティス トップ20:究極ガイド
社内のDockerfileのベストプラクティスを公開します│FORCIA CUBE│フォルシア株式会社
RUN adduser -D myuser && chown -R myuser /myapp
(-Dはデフォルト設定で追加している、-Rは指定dir以下を再帰的に所有権変更)USER myuser
(以降のRUNやENTRYPOINT等のINSTRUCTIONを実行するユーザを指定)
FROM ubuntu:latestRUN mkdir /app# "appuser" という専用のグループとユーザーを作成(ログイン不要のシェル設定)RUN groupadd -r appgroup && useradd -r -s /usr/sbin/nologin -g appgroup appuserWORKDIR /appCOPY . /app# ユーザー権限を変更(アプリケーションディレクトリの所有者を "appuser" に設定)RUN chown -R appuser:appgroup /app# 最小特権ユーザーで実行USER appuser# アプリケーションの実行コマンドCMD ["node", "index.js"]
Dockerfileの作り方を考え直したらすごく効率が上がった。 (zenn.dev)
■ビルドでイメージを作成
Dockerfileや材料ファイルのあるフォルダパスを最後に指定、-tはタグでイメージ名
docker build -t img_httpd001 ./
ビルド後にdocker runが必要docker container run -d --name cnt_httpd001 -v ${pwd}:/app img_httpd001:latest↓これが便利docker container run -rm --name cnt_httpd001 -v ${pwd}:/app img_httpd001:latest
■commitでコンテナからイメージを作成コンテナにexecで幾つかインスコする操作をしてからイメージにする等ができる
docker commit httpd001 img_httpd001
■コンテナ/イメージはDockerEngine上から移動できない
saveするとファイル化され、できるようになる
docker save -o save_img_httpd001.tar img_httpd001
ファイルからイメージとして取り込みたいときはdocker load
ファイル化せずにパブリックならDocker hubへ登録してもよい、プライベートレジストリを作ってもよい
その中にそれぞれリポジトリを持つ > docker push レジストリ/リポジトリ名:バージョン
■コンテナに命令する
2つの方法がある
1)docker exec → docker container execに変わった
起動中のコンテナ内でコマンドを実行するdocker container exec [option] <container> commandファイルを見るdocker container exec ubuntu1 cat ~/hello.txtコンテナに接続してbashを使うdocker container exec --interactive --tty ubuntu1 bash
2)docker run に引数を付ける→ソフトウェア(apache)が動いていない状態になり改めてdocker startが必要
docker exec -it コンテナ名httpd001 /bin/bash
apt install mysql-server など対話でコンテナにインスコできる
exit 抜ける
■Docker composedocker runコマンドの集合体、コンテナ等作って消すだけ(k8sはコンテナ等を管理する)
以前はdocker-composeコマンドで別ツールだったが今は統合済み
フォルダに1つだけdocker-compose.yml
基本はdocker runを実行せずにdocker composeしたい
手順は、1)Docker run方法で一応の検討>2)docker-compose.ymlの記述>3)docker composeコマンドの実行
docker run~~に対するdocker-compose.ymlとdocker composeコマンド の対比
1)docker run --name cnt_wordpress001 -dit --net=net001 -v wordpress001vol2:/var/www/html -p 8080:80 -e WORDPRESS_DB_HOST=mysql001 -e WORDPRESS_DB_NAME=wpdb001 -e WORDPRESS_DB_USER=wpu001 -e WORDPRESS_DB_PASSWORD=my-secret-pw wordpress
↓2) docker-compose.ymlの記述
version: "3"services: cnt_wordpress001: depends_on: - cnt_mysql001 image: wordpress networks: - net001 volumes: - wordpress001vol2:/var/www/html ports: - 8080:80 restart: always environment: WORDPRESS_DB_HOST=mysql001 WORDPRESS_DB_NAME=wpdb001 WORDPRESS_DB_USER=wpu001 WORDPRESS_DB_PASSWORD=my-secret-pw
cnt_mysql001: image: mysql:5.7 networks: - net001 volumes: - mysql001vol1:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD=my-root-pw MYSQL_DATABASE=wpdb001 MYSQL_USER=wpu001 MYSQL_PASSWORD=my-secret-pwnetworks: net001volumes: mysql001vol1: wordpress001vol2:
/// restartの設定値(コンテナが停止した時にどうするか?)
no =何もしない
always =必ず再起動する
on-failure =プロセスが0以外のステータスで終了したときは再起動する
unless-stopped =停止していたときは再起動しないがそれ以外は再起動する
Bashで終了ステータスよる条件分岐 | Codebase Blog
※bashは前に実行されたコマンドの終了ステータスは「$?」で取得できるが慣習的にコマンドが正常終了した場合は0を返す
/// その他の定義項目command =起動時の規定コマンドを上書きするentrypoint =起動時のENTRYPOINTを上書きするenv_file =環境設定情報のファイルを読み込む
他 container_name / dns / eternal_links / extra_hosts / logging / network_mode etc.
3)docker compose コマンド
up=イメージDL、コンテナ/nw/volの作成・起動
down=コンテナとnwの停止と削除、volとイメージは残る
stop=削除せず停止のみ
docker compose -f /home/a/docker-compose.yml up -d
docker compose up -d --scale unco001=3 (コンテナ名はput-folder-name_unco001_1, put-folder-name_unco001_2, put-folder-name_unco001_3になる)
-f ファイルの場所(省略でカレントパス)
-d バックグラウンド実行
--build コンテナ開始前にビルド
--no-build イメージが見つからなくてもビルドしない
-t コンテナ停止のタイムアウト(デフォ10S)
--force-recreate 設定やイメージに変更が無くてもコンテナを再生成 --no-create コンテナが存在していれば再生成しない
--abort-on-container-exit コンテナが一つでも停止したら全てのコンテナを停止 --remove-orphans 定義ファイルで定義されていないコンテナを削除 --scale 同じコンテナを複数作る
docker compose -f /home/a/docker-compose.yml down --rmi {all | local} 破棄後にイメージも削除、localの時はimageにカスタムタグが無いイメージのみを削除
-v volumesに記載されているボリュームを削除、但しexternalの指定を除く
--remove-orphans 定義ファイルで定義されていないコンテナを削除
docker compose -f /home/a/docker-compose.yml stop コンテナを停止
■Docker composeはコンテナ名を勝手につける
docker-compose.yml内は下記の通り、DockerEngine上のコンテナ名は変わるがdocker-compose.yml内のコンテナ名は変わず指定できるservices:
unco001~
unco002 depends_on:
- unco001
environment:
WORDPRESS_DB_HOST: unco001
↓
DockerEngine上のコンテナ名は put-folder-name_unco001_1 となる
DockerEngine上で操作したいときは docker ps -a 等で実際の名前を確認して操作する
■コンテナ デバッグ
3部: デバッグノウハウ ( 番外編 )|実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本 (zenn.dev)
====================
基本はLinuxの機能を使っているnamespaceで分離しファイル構造、ユーザーID、グループID、コマンド、ライブラリなど諸々をラップしコンテナ化し(単一の)プロセスとして動く↓
Dockerがやっている仕事は少ない
区切ってコンテナ
それら仮想ネットワークで繋ぐ
ボリュームの永続化
Dockerfileでイメージからイメージを作成Docker composeでdocker runを記述docker execでコンテナを操作etc.
Comment (0)
Navi: < 3 | 4 | 5 | 6 >
-Home
-Column [133]
-Europe [9]
-Gadget [77]
-Web [137]
-Bike [4]
@/// BANGBOO BLOG ///