ばぁど・うぉっちんぐ

セキュリティに強いWeb屋。自由と春を求めて羽ばたく渡り鳥。

このブログはGoogle Analyticsを利用しています

くだらないことで、Pythonにハマった話(Tupleのお話)

どーも。ばぁどです。

セキュリティに強いWeb屋を名乗っています。Webアプリケーション開発と脆弱性診断ができます。セキュア開発できます。

とはいえ、業務ではサイバーセキュリティが主になっており、普段はあまりプログラミングを行なっておりません。

なので、GitHubの草生やす作業を復活させようかなと思いました。

そんな、こんなで久々にくだらないことで、pythonにハマってしまったので事例を紹介。

事象

Pythonの文字列の切り取り作業を行なっていたのですが、思ったような挙動になってくれませんでした。

想定していた挙動

>>> 'Sample Text'[:6]
'Sample'

Sample Textという文字列の0桁目から6桁目の文字列を切り取って'Sample'という文字列を出力するプログラムです。 これだけ見れば、非常にシンプルで、ハマるようなところはありません。

Typoしていたプログラム

>>> 'Sample Text'[:6],
('Sample',)

実際にはまっていたプログラムは上記です。なんとも惜しいことに、文字列の切り取りの最後部分に,が追加されてしまっています。 非常に見つけにくい、なんともTypoらしい、 Typoだなと反省の日々。

Pythonにおいて、文字列の最後に,がつくことが、どのような結果を招くのでしょうか?

Tupleでした

docs.python.org

Pythonにはいくつかの型があります。 数値を扱う'int型'や、文字列を扱う'str型'、配列を扱うlist型などがあります。

その中の一つにtuple()というものがあります。

このtuple()というのが、list()と非常に似通っているのですが、list()とは違い不変な値を扱うのに長けています。

反省

Pythonの基本は勉強していたのですが、プログラムを書くのが久々でstr()だと思っていたデータが、Tuple()になっているのに気付くのが遅れてしまいました。

いやー。やっぱりしばらく触っていないと、感が鈍るものですね。

草生やし再開しようと思います。

闇の魔術に対抗するための正攻法

どーも。ばぁどです。

ハリーポッターは好きよりの好きです。 2023年のビッグニュースとして、ハリーポッターが年末(12月31日)より、配信がされるとのことです!!! 2023年の年末と、2024年の年始はハリーポッター見ながら実家でまったりと過ごそうと思います。

Amazon Prime Video 12月は「スーパーマリオ」や「ハリポタ」など魔法ワールド11作 - AV Watch

さて、IT業界にはさまざま闇の魔術があります。 その闇の魔術一つが、プロジェクトに埋め込まれる致命的なバグや緊急性の高い脆弱性が埋め込まれやすくする方法というものがあります。 今回は、これらのバグや脆弱性が埋め込まれないための正攻法をご紹介します。

余計な開発をするな。既にあるものを使いなさい。

要は実業務において「車輪の再開発」は行わないようにしましょう、ということです。 人間はミスをする生き物です。どんなに完璧だと思っていても、開発規模が大きくなるとそこに含まれるバグは多くなるのが定石です。 既に作成されているライブラリがインターネット上にあるのであれば、そのライブラリを使いましょう。

世界中に優秀なエンジニアがいます。顔も知らない誰かですし、言語が通じるかもわかりません。それでも、世界中にはたくさんの優秀なエンジニアがおり、常に新しい便利なライブラリを開発し続けてくれています。

筆者が新人の時にカレンダーのUIで日付を選択したい場合に自前で実装しようとした時に、近くにいた先輩に便利なライブラリがあることを教えてもらって感動をした覚えがあります。

jqueryui.com

もちろんライブラリを使用する際は、バグがないかや、本当にセキュリティ的に安全なのか、脆弱性が埋め込まれていないかは確認する必要はありますが、一般的に利用頻度が多いことが確認されているライブラリであれば、基本的には問題ないと考えて良いと思います。

仮に、既に開発がされているライブラリがあるにもかかわらず、自前でそれらの機能を実装しようとすると、そこにはバグや脆弱性が含まれる温床となります。 もちろん、安全な開発をできる環境があり、ソースコードレビューを適切に行い、それらの関数の脆弱性チェックなどができ、万全の体制を整えることができるチームなら杞憂で終わると思います。 しかし、大半のプロジェクトチームは運用チームからの新しい要望や、サービス拡大に伴うシステム改修で手一杯なはずです。それらのライブラリに対して、莫大なコストを支払う余裕ないのであれば、大人しく既存のライブラリを使いましょう。

身の丈のあった技術選定を

技術選定はプロジェクト開発において非常に重要です。 プログラム言語を何にするか?使用するフレームワークは何にするか?クラウド技術はAWSにするかGCPにするか? さまざまな場面で判断が迫られます。

技術選定を行う際は、さまざまな事情を考慮して選定されるのですが、稀に「技術的なチャレンジをするために最新技術を用いた開発」を行うという名目上、新しい技術が採用される場合があります。 しかし、この挑戦的な技術選定は稀に大量のバグと脆弱性を埋め込む可能性があります。

メンバーが不慣れな技術だと、開発する際に遅延が発生する可能性はあり、技術仕様を把握しきれていないことからくるセキュリティバグが埋め込まれる可能性が上がります。

しかし新しい挑戦をしないと技術的な成長が止まってしまうということも事実です。 新しい技術に挑戦する際は、事前にメンバーにはチュートリアルを回すことを徹底したり、挑戦したい技術の入門書を買ったり、一人でも良いので熟練者をプロジェクトチームに入れるなど、むやみに挑戦するのではなく、ある程度のリスクヘッジをした上で、挑戦するのが良いと思います。

奇を衒わず、正攻法で行きなさい

プロジェクト開発は常に基本を疎かにしないことをお勧めします。 奇を衒って、設計したプロジェクトはたいていがバグや脆弱性の温床になることが多くあります。

例えば、サーバから値を返却してクライアント側で描画する際は、フレームワークのルールに従って実装することで大抵の脆弱性は考慮せ図にWebアプリケーションを開発することができます。 特にXSSなどの画面に描画する際に発火するような脆弱性であれば、フレームワークのルールに従って実装することで無害化(エスケープ処理)された状態で、画面に出力されます。 しかしフレームワークのルールに従わずに実装した場合は、これらのバグや脆弱性が埋め込まれる可能性が高まります。

他にもGETメソッドでリソースの更新を行なったり、何でもかんでもPOSTメソッドで実装したりするなど、本来の利用目的とは違う場合や、開発者が意図した使用方法ではない場合などは、大体設計の仕方が変だったり、仕様を達成するために少々無茶な設計をしていることも多くあります。

このような設計があった場合や、ソースコードがあった場合はバグや脆弱性の温床となります。 常に技術は正しく使い、常に用法用量をお守りください。

まとめ

少しでも世の中のプロダクトがセキュアになりますように。

久方ぶりの開発合宿 2023.07.15-07.17

どーも。ばぁどです。

7月の海の日の三連休を使って開発合宿に行ってまいりました。 開発合宿への参加は、コロナ前が最後であったため約3年ぶりでしょうか。

今回は開発合宿に参加したので、そのアウトプットも含めて備忘録とします。

銚子の海
銚子の海

開発合宿とは?

2泊3日で、旅館に泊まり開発をするイベントです。 前職の企業のメンバーを主体に、開発合宿という文化があり、筆者も未だに参加させていただいているイベントになります。

イベントの内容としては、旅館に行きただひたすら開発を行うだけという非常にシンプルなものになります。

会場

毎回お世話になっている旅館は下記です。 土善旅館さん。(土には、があります。)

www.dozenryokan.com

毎回ご飯がとても美味しいです。 聞いたところ、こしひかりだったのですが、家でこしひかりを炊いても同じ味にならない・・・なぜ。

久方ぶりの開発合宿に参加して

.プログラミングは楽しいもの

現在の企業に転職して、そろそろ2年を超え、3年目に突入します。 筆者は現在、脆弱性診断を生業としており、プログラミングなどを用いた開発業務からは遠ざかっております。

開発合宿はコロナ禍は開催されないイベントであったため、開発合宿を目標にした開発なども行っていませんでした。

しかし今回の開発合宿で改めて感じたことが「ものづくりって楽しいですね。」ということ。

開発合宿は良いモチベーションになる

開発合宿はとても良いモチベーションになります。

なぜならば、開発作業というものに必然と向き合う時間が与えられるため、それに向けての最小限の準備をすることになります。 今回の開発合宿への参加がなければ、改めて開発に向き合うこともなかったので、個人的には良いきっかけになりました。

脆弱性診断のその先にあるもの、次のキャリアを考えているのですが、やはりもう少し開発に寄せたエンジニア人生を歩んで行きたいなと考えております。

開発の感覚を取り戻すの難しい

やはりブランクというものはありますね。 脆弱性診断を2年ほど行っていますが、業務でのプログラミングをする機会がめっきり減ってしまい、プログラミングの勘を取り戻すのに苦労しました。

やはりアルゴリズムを考える脳が、普段業務で使っている部位とは違う部分の脳みそを動かさなければいけないため、そういった疲れもあったのかなと思います。

業務でプログラミングを触らないとは言いましたが、ちょくちょく空き時間で業務改善ということで、Excelのマクロを組んだりはしているのですが、一晩考え直したら20行のコードが5行になったこともあり、一発で良いアルゴリズムを思いつく勘が鈍っているなと感じた直後の開発合宿だったので、そういった勘を取り戻すのにも、とても重要なイベントでした。

まとめ

開発合宿次回も行きまーす!

写真は今年のODD(Osake Driven Development)で使用したお酒。

ChatGPTにプログラムを書かせてみて、色々と検証してみました。プログラマはAIにより駆逐されてしまうのか?

どーも。ばぁどです。

ChatGPTが話題になり数ヶ月ですが、やっとアカウント登録して使ってみました。 プログラマの仕事が奪われるとか、色々SNSで見たりしましたが、 百聞は一見にしかず!と言うことで!

ポーカープログラムについて

筆者もPythonの練習がてら、ポーカープログラムを2,3年前に書いていました。 デッキからカードを引いたり、役を判定したりはできるのですが、まだ対戦機能は追加しておりません。(2023/03/26時点)

github.com

今回は、業務ロジックや業務知識などは必要ない、このポーカーのロジックをPythonで書いてもらいました。

ChatGPTによるポーカープログラム

最初のご挨拶

次に、ChatGPTが出して来てくれたポーカープログラム

出力されたPython

import random

# デッキの初期化
suits = ["ハート", "ダイヤ", "スペード", "クラブ"]
ranks = ["エース", "2", "3", "4", "5", "6", "7", "8", "9", "10", "ジャック", "クイーン", "キング"]
deck = [(rank, suit) for suit in suits for rank in ranks]
random.shuffle(deck)

# ゲームに参加するプレイヤーの数を入力
num_players = int(input("プレイヤーの数を入力してください: "))

# プレイヤーの手札を初期化
player_hands = [[] for _ in range(num_players)]

# カードを配る
for i in range(5):
    for j in range(num_players):
        card = deck.pop()
        player_hands[j].append(card)

# プレイヤーの手札を表示
for i, hand in enumerate(player_hands):
    print(f"プレイヤー{i+1}の手札: {hand}")

ChatGPTも言っていますが、デッキやカードを引くなどをしているだけで、役の評価や対戦ロジックはありません。 しかし上記コードだけだとトランプのデッキを作って、手札を配っているだけになります。 (それだけでも十分すごいのですが・・・) 変数の付け方がとても綺麗。 無駄なfor文もありません

# プレイヤーの手札を初期化
player_hands = [[] for _ in range(num_players)]

個人的に上のような書き方ではなく冗長に書かれた方が好きなのですが、今回は複数人での対戦を想定しているため、これは一つの形として良いですね。

次に評価ロジックも書いてもらいました。

出力されたPython

# 5カードドローの手札の役を判定する関数
def evaluate_hand(hand):
    # 手札をカードのランクとスートに分ける
    ranks = [card[0] for card in hand]
    suits = [card[1] for card in hand]
    
    # ランクの出現回数をカウントする
    rank_count = {rank: ranks.count(rank) for rank in ranks}
    
    # 手札にエースが含まれるかどうかを判定する
    has_ace = "A" in ranks
    
    # ストレートを判定するために、ランクを数値に変換する
    rank_values = {
        "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
        "T": 10, "J": 11, "Q": 12, "K": 13, "A": 14
    }
    
    # ストレートの判定
    sorted_ranks = sorted(set(ranks), key=lambda x: rank_values[x])
    is_straight = False
    if len(sorted_ranks) == 5 and (int(rank_values[sorted_ranks[-1]]) - int(rank_values[sorted_ranks[0]]) == 4):
        is_straight = True
    elif sorted_ranks == ["2", "3", "4", "5", "A"]:
        is_straight = True
    
    # フラッシュの判定
    is_flush = len(set(suits)) == 1
    
    # ロイヤルフラッシュの判定
    is_royal_flush = False
    if is_flush and has_ace and set(ranks) == {"T", "J", "Q", "K", "A"}:
        is_royal_flush = True
    
    # ストレートフラッシュの判定
    is_straight_flush = False
    if is_straight and is_flush:
        is_straight_flush = True
    
    # フォーカードの判定
    is_four_of_a_kind = False
    if 4 in rank_count.values():
        is_four_of_a_kind = True
    
    # フルハウスの判定
    is_full_house = False
    if set(rank_count.values()) == {2, 3}:
        is_full_house = True
    
    # スリーカードの判定
    is_three_of_a_kind = False
    if 3 in rank_count.values():
        is_three_of_a_kind = True
    
    # ツーペアの判定
    is_two_pair = False
    if list(rank_count.values()).count(2) == 2

こう言ったロジックを、確実に人間が書くよりも素早く的確に出してくれるのは驚嘆します。 ポーカーのロジック判定って、初学者にとっては良い勉強ツールだと思っています。 配列の扱い方や、ツーペアなどの現実で人間が判定しているロジックを、プログラムに落とし込むと言う練習は非常に重要です。 ただ、そう言ったロジックを学ぶのではなく、単純に作るだけなのであればAIが圧倒的に有利と言ったところ。

ただ、単純にPythonでコードを書くと、あまり保守性がないように見受けられます。 特にDeckやCardなど、クラス化できるような部分が、個人的には不満です。

そこで、ChatGPTにこう言った指示を出してみました。

出力されたPython

import random

# カードのランクとスートを表す定数
RANKS = ["2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"]
SUITS = ["C", "D", "H", "S"]

class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit
    
    def __repr__(self):
        return f"{self.rank}{self.suit}"
    
class Deck:
    def __init__(self):
        self.cards = [Card(rank, suit) for rank in RANKS for suit in SUITS]
        self.shuffle()
    
    def shuffle(self):
        random.shuffle(self.cards)
    
    def draw(self):
        return self.cards.pop()
    
class Hand:
    def __init__(self, cards):
        self.cards = cards
    
    def add_card(self, card):
        self.cards.append(card)
    
    def discard(self, card_index):
        return self.cards.pop(card_index)
    
    def __repr__(self):
        return ", ".join(str(card) for card in self.cards)

しっかりと指示を出せば、カードやデッキなどをクラス化したPythonを出力してくれましたね! すごい!

そして、既存のコードを読み込んでもらって改善してもらうこともできました。

1.Playerクラスにプレイヤーの名前を保存するname属性を追加します。

class Player:
    def __init__(self, name):
        self.name = name
        self.hand = []

2.対戦するプレイヤーの名前を取得する関数を追加します。

def get_player_names():
    print("Enter player names (comma separated): ")
    names = input().strip().split(",")
    return names

3. プレイヤーの名前を取得して、Playerオブジェクトを作成する関数を追加します。

def create_players():
    names = get_player_names()
    players = []
    for name in names:
        player = Player(name.strip())
        players.append(player)
    return players

4. ゲームの進行を制御するmain関数内に、create_players関数を呼び出してプレイヤーを作成し、対戦させる処理を追加します。

def main():
    deck = Deck()
    players = create_players()
    for player in players:
        print("Player: {}".format(player.name))
        hand = deck.draw(5)
        player.hand = hand
        print("Hand: {}".format(hand))
    winner = determine_winner(players)
    print("Winner: {}".format(winner.name))

if __name__ == "__main__":
    main()

実際に上記コードを追加して、ソースコードが正しいかのチェックはまだしておりません。 今まで億劫だったので、やっていませんでした。 なので、ChatGPTに投げてみました!

import random

def deal(deck, num_cards):
    hand = []
    for i in range(num_cards):
        card = deck.pop(random.randint(0, len(deck) - 1))
        hand.append(card)
    return hand

deck = Deck()
deck.shuffle()
player1_hand = deal(deck.cards, 5)
player2_hand = deal(deck.cards, 5)
# 対戦
player1_score = judge(player1_hand)
player2_score = judge(player2_hand)

print("Player1 hand:", player1_hand, "Score:", player1_score)
print("Player2 hand:", player2_hand, "Score:", player2_score)

if player1_score > player2_score:
    print("Player1 wins!")
elif player1_score < player2_score:
    print("Player2 wins!")
else:
    print("It's a tie!")

内部のロジックなどは、書いてくれてはいませんがある程度機能の中身も理解できる。 こう言った、人間が必死に考えずともロジックを投げてくれるなーという感覚ではあります。

プログラマはAIにより駆逐されるのか?AIが普及してもプログラマに必要な技術とは?

個人的な答えは、平坦なプログラマは駆逐されます。 それこそ、指示待ちのプログラマやプログラムを書くだけのプログラマです。 しかし優秀なプログラマはChatGPTなどのAIを用いて、更に高度なエンジニアリングをできるようになるかなと思います。

プログラムの良し/悪しを判断する技術

AIが出してくれるプログラムが良いものかどうかを判断するのは人間です。 用件定義不足や、AIが間違える場合もあります。 それらのAIが出してきたコードが正しい動きをするのか?と言うのは非常に重要な部分だと思います。

今回はポーカーアプリを作ってもらいましたが、じゃあ今後プログラムにおいてプログラマがポーカーのロジックを考えなくて良いか?というと、そう言うわけではないと考えています。 やはりプログラムロジックを考える力がないと、 実業務をプログラムとして書き起こすことは難しいですし、複雑なビジネスロジックをどこまでAIに任せるかはまだ十分な議論がされていません。

ベンチャーであれば、あるほどAIの業務の取り組みは早いかもしれませんが、ガチガチなルールで縛られた企業ではAIの活用にはまだ数年かかるかもしれませんね。 どちらにせよ、AIはツールとして活用するべき強力なツールだと学びました。

IT領域にも”藤井聡太"のような異次元のエンジニアが現れる

チェス業界や将棋業界などの、ある特定のテーマにおけるAI研究は盛んに行われていました。 筆者が高校生の時には既に研究が始められており、チェスの王者がAIに負けたと言うコラムを読んだ覚えがあります。

そんな現在将棋界を席巻している藤井聡太さんは、子供の頃からAIを用いて将棋の勉学に励んでいたそうです。 もちろん現役の棋士の皆様もAIを用いた将棋研究は行なっていますが、幼少期の頃からAIによる将棋の研究をしていることから、積んでいるエンジンがそもそも違うといった各棋士のコメントをよく読みます。

ChatGPTなどのAIが今後更に普及することにより、プログラムの学習時点で効率よくAIを用いる超絶エンジニアが出てくる可能性があります。 そう言ったすごい若手エンジニアとも戦わなければいけないとなると、余計窮屈になってしまうなと考えるだけで頭が痛いですね。

最後にAIに聞いてみた

今のところは大丈夫っぽいですね(苦笑

”適応障害”と診断されたエンジニアの復職までの奮闘記

どーも。ばぁどです。 個人的な備忘録です。

今年のとある時期に、”適応障害”と診断されて一時期休職しておりました。 今回は自身の適応障害になった事象と、復帰までの備忘録になります。

※筆者は精神科に関するプロフェッショナルではありません。 本記事に記載されている医療的な内容に関して責任は負いかねます。適切に主治医と相談をしてください。

適応障害とは

自分の置かれた環境にうまく慣れることが出来ず、不安感や抑うつ気分、不登校、出勤拒否、対人トラブルなど、様々な症状・問題が出現し、社会生活に支障をきたす状態です。
適応障害は様々な要因で起こりえますが、特に就学や就職、転職、結婚、離婚など、生活環境が大きく変わった際に発症しやすいと言われています。ご本人が「新たな環境にうまく適応しなくては」と思ってもなかなか思い通りに事が運ばない、そのようなストレスが原因となります。
不安感を引き起こしている原因ははっきりしている事が多く、原因から離れることで症状の改善が見込めます。しかし現実には、転職や転校などの方法で環境を変えることが難しい状況もあります。ストレスの原因から離れることが出来ずに症状が長期間続くこともあります。

https://sobani-clinic.com/maladjustment.htmlより引用

Google検索で一番上に出てきたメンタルクリニックの説明を引用させていただいております。 他のサイトでも同じようなことが書かれており、実際に私も主治医より上記のような説明を受けていたので、内容としては問題ないはず。

筆者としましては、最初に「適応障害」と診断された時は「あ、なんか聞いたことある!」くらいの感じでした。

具体的な症状とストレスの原因

具体的な症状です。 具体的な症状は、業務中に出ました。 仕事中に急に不安になる、動悸が止まらない、注意力散漫になるなど、普段とは違うことが多々ありました。

あまりにも普段とは違うことがあり、特に普段はミスをするはずがないところでのミスが目立ちました。 ミスをした上で自分でさらに自分を追い込み、さらにメンタルに不調をきたすという悪循環に陥りました。

少しプライベートでも影響は出ており、普段はあり得ないミスを日常生活でもしていたので、やはり変だったのでしょう。

ただ、深刻な症状は業務中にのみ現れていたため、プライベートでは元気になります。 仕事終わって数十分すれば、気分は晴れやか。 今日はご飯何を食べに行こうとか、この後何の映画をアマプラで見よう!とか、色々と”楽しい”ことは考えることができました。

ストレスの原因としては、業務に出ていたので間違いなく仕事内容です。 1年弱同じ仕事をしていたのに、突然なったということなので、 おそらく直近の案件で変なストレスの掛け方をしてしまったのかなと分析しております。

元から、あまり残業を好まない考え方をしていたので、 少し残業?と言いつつも、あまり残業もしていなかったのでさてはてなんでしょう?といった感じです。

どのように治療を行ったか

ひたすら仕事を忘れました。 学生時代の友人に連絡を取り、旅行やご飯、ドライブに行く計画をひたすら立てました。 一人になると、どうしても仕事のことを考えたり、仕事に戻れるのか心配になったりしてしまうのですよね。 そういう状況に陥らないためにも、ひたすら人に会う予定を入れておりました。

旅行もなるべくするようにして、宮城旅行、静岡弾丸旅行、島根旅行など時間”だけ”はあるので、旅行しまくりました。 旅行やご飯に付き合ってくれた学生時代の友人に感謝でございます。

復職一ヶ月前(休職してから3週間後くらい)から、少しずつ勉強を再開。 勉強ではなくても良いのですけれども、何か机に向かって作業をするようなことに慣れることが目的でした。 仕事に関する勉強は少し辛そうなので、ずっと取得したいと思っていたダイビング資格の勉強をしました。 ダイビングは物理や自然保護などを学んだ後、海での実技の講習もあるので海においてリフレッシュすることができ、非常に良いリハビリだったと思います。

その後はここ数年チャレンジ目標においていたCEHを受験。無事に合格することができました。

復職!

まぁ、リフレッシュに全振りしていたので二ヶ月ほどで職場復帰。 最初の方は職場に慣れる意味で、時間制限(勤務時間は午前中のみや短期)があるかなと思ったら、二ヶ月での復帰は早いらしく最初からフルタイムでした。 まぁ個人的にも初日から問題なくフルタイムで働くことができたので、問題ないです。

適応障害になってみて。

マジでメンタルおかしくなると”気合い”とかでどうにかなるものではないですね。 思った以上に、自身の心の舵取りができなくなる? 舵が壊れてしまうので、大海原をただただ漂流するような不安感、焦燥感に駆られます。

適度にリフレッシュしていくことが大事。 頑張りすぎず、マイペースに。

あともっとプライベートや趣味に時間を割こうと考えております。 社会人になって、システムエンジニアを仕事として結構勉強ばかりしてきた。 でも、その勉強も一呼吸ついてスロースペースにしても良いのかなと。

引越しやプライベートでやりたいことなど、色々とやりたいことが増えてきたので復調したのでしょう。

そんないろいろな学びも得ることができた休職二ヶ月でした。

まとめ

健康第一!

※写真は休職期間中に訪れた島根県隠岐諸島海士町の港と海

Amazon Cognitoが脆弱性を入れ込まないと言う面でも素晴らしいと言う話

どーも、ばぁどです。 セキュリティエンジニアやっています。 元々はWebアプリ開発をやっていました。 現在は脆弱性診断を主にやっております。

最近、プライベートでAmazon Cognitoを利用したアプリケーションを触るタイミングがありました。 前から、Amazon Cognitoの存在はなんとなく知っておりましたが、少し調べてみるとサイバーセキュリティ的な観点で「あぁ脆弱性がなくなる良いものだ」と言う感想を持ちました。

物は作り込まない方が脆弱性は入り込まないと言う鉄則

筆者がWebアプリ開発者として、Webアプリを開発していた頃のお話です。 「自身が作るよりもライブラリなどに任せた方が結果的に安全なWebアプリケーションが作れる」と言う旨の発言をする同僚がいました。 当時の筆者は、あまり理解できていなかったのですが今なら概ね同じ意見であります。

例えばWebアプリケーションのモデル層で、DBを操作するSQLを発行する場面。 今ならDBを操作するSQLを発行するためのライブラリは多くの言語、フレームワークで採用されており、それらのライブラリを正しく扱えば、SQLインジェクションなどの脆弱性は基本的に防ぐことが可能です。

クロスサイトスクリプティングなども同様に、フロントエンド側の技術を正しく扱えばエスケープ処理を施した上で画面への描画が可能です。

これらは誤解を恐れずにいうと、利用ライブラリがOSSとなっており幾人もの凄腕エンジニアの方々のチェックが入ることから脆弱性が存在しないことが担保されています。

この既に作られているライブラリの安全性を理解していないと、自前のライブラリを使うとか、社内独自のフレームワークという発想になり、そもそもそこに脆弱性が存在していて、脆弱性だらけのWebアプリケーションを量産するという構図になっている企業を稀に見ます。

基本的には「作り込まない方が脆弱性は入り込みません」。

Amazon Cognitoが脆弱性を入れ込まないと言う面でも素晴らしい

さて、Amazon Cognitoのお話になります。 Amazon Cognito とは awsが提供するサービスの一つになります。

Amazon Cognito は、ウェブおよびモバイルアプリの認証、承認、およびユーザー管理機能を提供します。ユーザーは、ユーザー名とパスワードを使用して直接サインインするか、Facebook、Amazon、Google、Apple などのサードパーティーを通じてサインインできます。
Amazon Cognito の主な 2 つのコンポーネントは、ユーザープールと ID プールです。ユーザープールは、アプリユーザーのサインアップとサインインオプションを提供するユーザーディレクトリです。ID プールは、AWS の他のサービスに対するアクセスをユーザーに許可します。ID プールとユーザープールは別々に使用することも、一緒に使用することもできます。

docs.aws.amazon.com

要するに、Amazon Cognitoを用いることでログイン処理(認証、承認)を比較的工数をかけずに作成することができます。 ログイン処理ということなので、もちろんユーザ管理機能や各種アカウントとの連携なども可能です。

ログイン処理(認証、承認)は一定の力量を持つエンジニアが設計、開発しなければならない

ログイン処理とは、会員制のWebアプリケーションを使用する際に、そのWebアプリケーションに”誰が”、”どういった権限”で利用するかのチェック機構になります。 ユーザID、パスワードを入力した際に、ユーザID はテーブル内に存在するか?パスワードは合っているか?などのチェック機構が基本的に入ります。 ユーザID及び、パスワードが合っていて初めてログインを行うことができます。

しかしログイン処理は、Webアプリケーションを利用していないユーザでもアクセスすることができる重要なシステムです。 例えば、存在しないIDを入力した際に出すエラーメッセージと、既に存在するIDを入力した際に出すエラーメッセージを工夫しないと、攻撃者に対してユーザ情報について教えてしまう可能性があります。

このように、ログイン処理は一定の力量を持つエンジニアが開発しなければ、攻撃者にとって絶好の攻撃ターゲットになってしまうことは想像に難くありません。

また、ID連携機能は更に高い技術力が求められます。 Open ID Connect などの企画はありますが、それらの仕様を把握した上でテーブル設計を行い、漏れなくロジックを書くことによって初めて実現されるのが他システムとのID連携になります。 正直筆者も実装を行うとなうと、身震いしてしまうくらいには避けたいシステム内容です。

Amazon Cognitoが素晴らしい。

そこでAmazonから提供されている、Amazon Cognitoです。 Amazon Cognitoを用いれば上記の本来はログイン機能を実装する際に考慮しなければいけない内容を考慮せずに、Amazonデファクトスタンダードに合わせてログイン機能を用いることができます。

ログイン処理を開発する際に考慮するべき、ユーザのテーブル設計などもAmazonが用意してくれています。 この考えなくて良いというのと、あらかじめセキュリティが担保されているというのは、Webアプリ開発の知見を持たないベンチャー企業にはとても有益なのではないでしょうか。

正直エンジニアとしての経験をまともに3〜5年くらい続けていればログイン機能の一つや二つは開発する機会はあるでしょう。 しかしセキュアなログイン機能を完璧に開発できるかは、その当時の仕様やソースコードのチェック体制にも絡んでくる要素であり、筆者自身もセキュアなログイン機能を実装するのは可能ですが、大きな工数が必要になります。 こういった工数削減という面から見てもAmazon Cognitoは非常に有益です。

また、ログイン時のパスワードのポリシーなども既に用意されているものを扱えば、基本的には安全なものになります。 例えばパスワードの最低文字数、最長文字数や文字種別などです。

docs.aws.amazon.com

脆弱性診断のタイミイングでこれらの要件に不備があることを指摘されても、管理コンソールから設定を修正することでセキュアなログインポリシーの反映ができます。 これを自前で開発していると、if分を追加したりだとか、エラーメッセージをどのように表示するかなどを考える必要があります。

こういった点から、Amazon Cognitoなどを利用した方がセキュアなログイン機能を得ることができ、とても有益だと筆者は考えました。

新しい技術は正しく採用することが吉である。

筆者個人的な感想ですが、新しい技術は正しく採用していくことは吉だと考えています。 特にAmazon Cognitoのように、採用するだけで一定のセキュリティを担保できるような技術は採用の価値は十分にあるでしょう。 個人的にはAmazon Cognitoの管理画面上で、セキュリティポリシーなどをチェックボックスで入力することで変更できる部分はとても感動しました。(まぁそりゃそうなのだが)

しかし技術選定はケース by ケースであり、 こういった最新の技術を使用するのが会社のルール的に難しい場合もあれば、 どうしてもAmazon Cognitoの仕様がWeアプリケーションの仕様とマッチしない場合もあるでしょう。

そういった場合は、自身の置かれている環境と、新しい技術のメリット/デメリットを考慮した上で、採用を検討してもらえればと思います。

リベンジ成功!!CEH合格体験記!!

どーも。ばぁどです。 久々のブログ更新になりました。 ちと最近色々ありまして、勉強とかしないようにしていたのでアウトプットも少なめ。

そんな中、CEHに合格したので合格体験記を書いていきます。

CEHとは

CEHとはCertified Ethical Hacker という略で、倫理的な認定ハッカーという意味を持つ資格です。 アメリカの企業であるEC-Councilが主催しており、海外では一定の評価を得られているセキュリティ系の資格になります。

www.eccouncil.org

初挑戦は2020年12月

はい。筆者、一度CEH落ちています。 当時は、独学で頑張ろうとなり、EC-Councilにセキュリティに関して2年の実績ありますよと、拙い英語で説明を行い、海外から電話がかかってくるなどの難所を突破し、無事に受験資格を得た上で試験に挑みました。

当時はCEHのトレーニングを受ける以外では日本語での受験をすることができず、言語を英語で挑戦しました。 その結果、敗北。

毎朝英会話をやっているので、 少し英語に自信はあったのですが、やはり試験を受けるほどまで英語力が醸成されていなかった模様。

また、敗着の原因としてはnmapのコマンドなどを勉強しておらず、3問ほど全て落としてしまったのも原因に挙げられるかと思います。

念願のリベンジ!2022年10月

そんな、CEHに敗北してから2年後、CEHへのリベンジを果たしました。

転職をした先の会社でCEHのトレーニングを受ける人を募集しており、飛びつきました。 2021年中にトレーニング自体は終了。 仕事の繁忙期や、メンタル・体調の調整、勉強時間をなんとか捻出し、トレーニングを受けた後10ヶ月ほどで試験に挑みました。

勉強期間は、メンタルの浮き沈みがあったのですがトータルで2ヶ月半くらいかなと思います。 CEHのトレーニングで配布されたテキストに付箋を貼りながら、必死にノートにまとめ、後述するPocketPrepで苦手分野を埋めていきました。

その結果、72%というギリギリのスコアで、無事にCEHに合格ました。

個人的なCEHを受ける上で気をつけるべきところ

範囲が非常に広い

試験範囲が非常に広いです。 また、IPAの試験とは違いベンダーの製品なども出てきます。

このことからある程度日本語でセキュリティを一通り勉強してから挑戦した方が良いかなと思いました。

筆者は4年前くらいに情報処理安全確保支援士に合格したり、一時期サイバーセキュリティの講師なども行っていたため、その際の知識が非常に役立ったと思います。

特に情報処理安全確保支援士は、CEHの試験範囲と重なる部分もあり、情報処理安全確保支援士の試験範囲ではない部分を苦手分野として、集中的に勉強を行いました。

このように試験範囲は非常に広いので気をつけてください。

nmapのコマンドは確実に覚える

Nmapのコマンドは確実に覚えた上で、試験に臨んでください。 試験問題は毎回ランダムのはずですが、3問-4問ほど出てきました。 普段業務で使用していればおそらく問題ないのですが、筆者はnmapを業務では使用していない側の人間。

Nmapの基本的なコマンドは下記サイトを参照。

nmap.org

Nmapのコマンドは、SYNやFINスキャン、Xmasスキャンなどそれぞれがどういったスキャンなのかをセットで覚えると吉です。

中途半端な日本語翻訳に注意

CEHは基本的に英語です。 英語のものを日本語に訳して、意味を理解するといった作業が非常にありました。

例えば、OSI参照モデルだけでも日本語と英語で表現が違ったりします。 英語で初めての概念を勉強していたら、日本におけるOSI参照モデルやん!とかありました。

知らないツールは事前にまとめる、覚えていないものは諦める

後述する、模擬試験サイトである程度自信を持った上で挑みましたが、それでも初めて聞くツールが存在しました。

もしかしたらテキストをひたすら探れば、記載があったのかも知れませんが、ツール群に関しては当日の感でした。 対策の試験勉強としてはMACスプーフィングやDosなどの目的別のカテゴリを作成して、ひたすらツールをまとめていくという対策はできたかなと少し反省しました。

参考にしたサイト、本、勉強会など

Pocket Prep

個人的に一番活用させていただいたサービスです。 1,300問の模擬問題があり、使いやすさも抜群。 言語は英語のみなのですが、Google翻訳でひたすら翻訳すれば問題ないです。

www.pocketprep.com

Certified Ethical Hacker(CEH) Online practice exam

こちらも便利。 Pocket Prepでは出ない問題がいくつかあったので、知識の補填に役立てました。 しかしV10までしかなく、2022年10月現在v11での試験になりますので、バージョンが違うというのは注意してください。

ceh.cagy.org

ホワイトハッカー入門

CEH対策に役だった本の一冊です。 内容は少し自信の知っている知識と食い違う部分もありましたが、あまり日本語で資料がまとまっていない上で、日本語で出してもらえている本なので非常に重宝しました。 特にnmapのコマンドのまとめ方は、この本が一番上手だったと思います。

book.impress.co.jp

勉強会(Conpass)

Conpassで有志により運営されている勉強グループです。 CEHホルダーが何名も参加してくれているので、勉強の仕方や、勉強してわからないことなどの質問もできると思います。 筆者も2回〜3回参加させていただき、有益な情報を得ることができました。 大変ありがとうございますmm 次回勉強会決まりましたら、ご挨拶程度で伺おうかなと思います。

ceh-studygroup.connpass.com

まとめ

CEH合格したぞーーーー!! 20代の頃に、30歳までにハッカーになる!と目標を掲げ、ギリギリ30歳でCEHの取得ができました。

別にCEHを取ったからといってハッカーになれたわけではないと思いますが、それでも資格として残るのは嬉しい限りでございます。

ひたすら続く社会人、ITという長い道。 その一つの通過点として、CEHというものがあったのかなと思います。 引き続き、日々精進です。

2022年11月16日追記

この記事を勢いで出した後、気づいたことがある。 それがASPENの画面にログインした時に気づいた。

ご覧の通り、一度私はCEHを落ちている。 当時は英語のリーディングが弱すぎて、落ちたものだと思っていた。 しかし、得点のパーセンテージを確認して把握した。

英語で受けたCEH v10

日本語で受けたCEH v11

上記を見てもらえれば分かる通り、実際は私が落ちた(Fail)したv10の方が1%多く得点している。 それにもかかわらず、今回受けた試験で72%で合格することができた。

結論:合格ラインが引き下げられたから合格できた。

ちゃんちゃん♪