- 投稿日:2019-05-06T22:09:51+09:00
自分用勉強メモ9日目
tips
502 Bad Gateway
HTTPのエラーコードの1つ.
400番台がクライアント側のエラー(File not found とか)であるのに対し,500番台はサーバ側のエラーを示す.
今回は,ゲートウェイやプロキシが不正なリクエストを受け取ったことを示している.参考:HTTP502(Bad Gateway)の原因と対処法
SQLインジェクションの1つの解
管理者でのログインを試みる際,ユーザ名が
admin
で決め打ちだった場合,admin'--と入力すればパスワードが何であれログインに成功する.
調べた知識
Base64
英数字と「+」「-」「=」のみを使って,マルチバイト文字等をエンコードする方式.これによって,英数字+@しか使えない通信環境でもマルチバイト文字等を扱うことができる.
エンコード・デコードには以下のサイトが便利である.ヴィジュネル暗号
換字式暗号の1つ.
アルファベットの対応表をもとに平文を暗号化する.
1つ1つ目で追って解読しても解けるが,スクリプトを書いて楽にしたい.vigenere_cipher.pyimport sys class MyVigenere: def encode(text, key): ret = '' for i in range(len(text)): offset = (ord(text[i]) + ord(key[i]) - 2 * ord('a')) % 26 ret += chr(ord('a') + offset) return ret def decode(text, key): ret = '' for i in range(len(text)): offset = (ord(text[i]) - ord(key[i])) % 26 ret += chr(ord('a') + offset) return ret if __name__ == '__main__': plaintext = sys.argv[1] key = sys.argv[2] flag = MyVigenere.decode(plaintext, key) print(flag)John The Ripper
パスワードクラッキングツール.
以下,Ubuntuでの実行例を示す.// ツールのインストール # apt install john // パスワードファイルとシャドウファイルを結合する $ unshadow passwd shadow > tmp // johnコマンドに渡す $ john --show tmprobots.txt
検索エンジンのクローラーのアクセスを制限するためのファイル.
見せたくないページはここに記述するらしい.picoCTF
きなこ(@kinako_software)さんのブログ(こちら)を拝見して,cpawCTFの次はこれをやるといいよと書いてあったので取り組んでみる.
ヒントが書かれているので,もしわからなかったとしても調べればなんとかなりそう.Logon
ユーザ名とパスワードを入力してログインする.
何を入力してもログインに成功するが,adminでログインしたい.
Cookieを見ると,ログイン成功後にadmin
という変数がFalse
で格納されている事がわかる.
これをTrue
に書き換えてリロードするとログイン成功.Recovering From the Snap
ディスクイメージファイルが渡される.
file
で見てみると,FATであることがわかる.
Ubuntuで,以下のコマンドを実行してマウントする.# mount -t vfat animals.dd /mnt/animal/これで
/mnt/animal/
以下に4つの画像が現れた.
Linuxでは,jpgファイルはeog
コマンドで開くことができる.
しかし,どの画像を見てもフラグに関係するようには思えない.
ヒントを見てみると,いくつかのファイルが削除されてしまっているらしい.
FTK Imagerというツールを使うと,ディスクイメージをマウントしたときに削除済みのファイルにもアクセスできるらしい.
MacやLinuxではコマンドラインツールしか利用できず使い方が難しかったので,Windows版をダウンロードした.
与えられたイメージを開くと,フラグが書かれている画像が削除されていることがわかる.
そのファイルを開けばフラグを獲得できる.admin panel
与えられたpcapファイルをWiresharkで開く.
/login
にPOSTしている部分があるので,そのパケットを見ると,パスワードのところにフラグが書かれている.hertz
換字暗号だったので,便利そうなツールを調べたところ,quipqiupというのを見つけた.
「Puzzle:」の部分に暗号化されたテキストを貼り付けて「Solve」を押すだけ.
- 投稿日:2019-05-06T12:50:19+09:00
N+1の予感がしたらincludesを追加?
こんにちは!
入社したてのころ、右も左もわからずにコーディングをしていました。
そんな中で、僕もよく悩まされたN+1についての対策について簡単にまとめてみました。
N+1は簡単に防げてパフォーマンスをあげることができます。
すぐできて、効果大なのでぜひ実践してみてください!そもそもN+1とは
SQLクエリが 「データ量N + 1回 」走ってしまい、取得するデータが多くなるにつれて(Nの回数が増えるにつれて)パフォーマンスを低下させてしまう問題です。
N+1問題 / Eager Loading とは
(引用させていただきました)→簡単にいうとデータ取得の際、余計にSQLを発行してしまいパフォーマンスを下げてしまうことです。
テーブルの定義
例えば配列展開でBook(本)からAuthor(著者)の名前を出力したい場合(以下ER図&作成データになります)。
念の為コードも
Author
class Author < ApplicationRecord has_many :books endBook
class Book < ApplicationRecord belongs_to :author endデータの用意
author(諫山さん)が6冊の本(book)のリレーションを持っています。
irb(main):004:0> Author.all # 全てのAuthorレコード Author Load (0.5ms) SELECT "authors".* FROM "authors" +----+--------+-------------------------+-------------------------+ | id | name | created_at | updated_at | +----+--------+-------------------------+-------------------------+ | 1 | 諫山創 | 2019-05-05 10:44:51 UTC | 2019-05-05 10:44:51 UTC | +----+--------+-------------------------+-------------------------+irb(main):003:0> Book.all # 全てのBookレコード Book Load (1.3ms) SELECT "books".* FROM "books" +----+---------+-----------+-------------------------+-------------------------+ | id | title | author_id | created_at | updated_at | +----+---------+-----------+-------------------------+-------------------------+ | 1 | 進撃の1 | 1 | 2019-05-05 10:46:17 UTC | 2019-05-05 10:46:17 UTC | | 2 | 進撃の2 | 1 | 2019-05-05 10:46:25 UTC | 2019-05-05 10:46:25 UTC | | 3 | 進撃の3 | 1 | 2019-05-05 10:46:28 UTC | 2019-05-05 10:46:28 UTC | | 4 | 進撃の4 | 1 | 2019-05-05 10:46:31 UTC | 2019-05-05 10:46:31 UTC | | 5 | 進撃の5 | 1 | 2019-05-05 10:46:35 UTC | 2019-05-05 10:46:35 UTC | | 6 | 進撃の6 | 1 | 2019-05-05 10:46:38 UTC | 2019-05-05 10:46:38 UTC | +----+---------+-----------+-------------------------+-------------------------+irb(main):004:0> Author.first.books # 諫山さんが6冊の本(book)のリレーションを保持 Author Load (1.7ms) SELECT "authors".* FROM "authors" ORDER BY "authors"."id" ASC LIMIT ? [["LIMIT", 1]] Book Load (0.2ms) SELECT "books".* FROM "books" WHERE "books"."author_id" = ? [["author_id", 1]] +----+---------+-----------+-------------------------+-------------------------+ | id | title | author_id | created_at | updated_at | +----+---------+-----------+-------------------------+-------------------------+ | 1 | 進撃の1 | 1 | 2019-05-05 10:46:17 UTC | 2019-05-05 10:46:17 UTC | | 2 | 進撃の2 | 1 | 2019-05-05 10:46:25 UTC | 2019-05-05 10:46:25 UTC | | 3 | 進撃の3 | 1 | 2019-05-05 10:46:28 UTC | 2019-05-05 10:46:28 UTC | | 4 | 進撃の4 | 1 | 2019-05-05 10:46:31 UTC | 2019-05-05 10:46:31 UTC | | 5 | 進撃の5 | 1 | 2019-05-05 10:46:35 UTC | 2019-05-05 10:46:35 UTC | | 6 | 進撃の6 | 1 | 2019-05-05 10:46:38 UTC | 2019-05-05 10:46:38 UTC | +----+---------+-----------+-------------------------+-------------------------+コンソールで実行
配列展開でBookから親モデルのAuthorのnameを呼び出すとBookのデータ数分(6個)SQLを発行してしまいます。
→つまり5回もSQLが無駄に発行されてしまうのです。books = Book.all > Book Load (0.2ms) SELECT "books".* FROM "books"irb(main):037:0* books.each do |book| irb(main):038:1* book.author.name irb(main):039:1> end Author Load (0.6ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] irb(main):040:1>この無駄なクエリを防ぐにはincludesを追加するのがもっとも簡単です
includes追加
books = Book.all.includes(:author) #追加 Book Load (2.1ms) SELECT "books".* FROM "books" Author Load (0.2ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? [["id", 1]]お気づきでしょうか、includes追加により関連レコード(author)も一緒に取得されています。
→つまり、Bookと一緒に紐づいたAuthorモデルのレコードも取得し変数に代入していることになります。Before
books = Book.all > Book Load (0.2ms) SELECT "books".* FROM "books"books = Bookモデルの全てのデータ
After
books = Bookモデルの全てのデータとそれらにひもづくAuthorデータこの状態でもう一度booksを展開してみましょう!
irb(main):051:0* books.each do |book| irb(main):052:1* book.author.name irb(main):053:1> end irb(main):054:0>今度は展開のたびにAuthorを取得していません。
SQLの発行をおさえてパフォーマンス低下を防ぐことができましたね。includesで色々なリレーションを取得する
先ほどはN:1(Book:Author)でのパターンでしたが、実際はもっと複雑な利用パターンが多いと思います。
そんな時に利用できる書き方をご紹介します。N:1 = Book:Author
books = Book.all.includes(:author)こちらは先ほどのパターンでしたね
N:1:1 = Book:Author:Profile
では、Authorのプロフィール情報を保存するAuthors::Profileがあった場合
books = Book.all.includes(author: :profile) Book Load (1.6ms) SELECT "books".* FROM "books" LIMIT ? [["LIMIT", 11]] Author Load (0.4ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? [["id", 1]] Authors::Profile Load (0.4ms) SELECT "authors_profiles".* FROM "authors_profiles" WHERE "authors_profiles"."author_id" = ? [["author_id", 1]]N:1:1:1 = Book : Author : Profile : ProfileImage
さらにProfileに1つのプロフィール写真Authors::ProfileImageひもづく場合
books = Book.all.includes(author: [profile: :profile_image]) Book Load (0.5ms) SELECT "books".* FROM "books" LIMIT ? [["LIMIT", 11]] Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? [["id", 1]] Authors::Profile Load (0.2ms) SELECT "authors_profiles".* FROM "authors_profiles" WHERE "authors_profiles"."author_id" = ? [["author_id", 1]] Authors::ProfileImage Load (0.1ms) SELECT "authors_profile_images".* FROM "authors_profile_images" WHERE "authors_profile_images"."id" = ? [["id", nil]]逆に1:N(Author:Book)なら?
これはリレーションを使い関連データを全て取得できますね。> Author.first.books Author Load (0.3ms) SELECT "authors".* FROM "authors" ORDER BY "authors"."id" ASC LIMIT ? [["LIMIT", 1]] Book Load (0.3ms) SELECT "books".* FROM "books" WHERE "books"."author_id" = ? [["author_id", 1]]N+1の予感とタイトルにありますが、余計にクエリを投げるケースは配列展開が多いと思います。
慣れていない方はeachやmap, selectなど配列展開のメソッドを使う際にN+1が起きていないかぜひ意識してみてください!
- 投稿日:2019-05-06T01:19:17+09:00
【Big�Query】 商品データを分析・可視化
概要
ECサイトの商品データ約30,000件をBigQueryで集計、Googleデータポータルで可視化・分析し、データの特徴や傾向把握を試みます
対象データ
今回対象とするのは、「Amazonにおけるインナーウェア製品データ」です
上記のように、「商品名/価格(ドル)/ブランド名/レビュー件数..」等のデータが約30,000件入っています
Kaggleにて公開されているので、CSVファイルとしてダウンロードしてきます※実際のデータでは実在のブランド名が使われていますが、この記事内では全て仮名に置き換えています
▼ BigQueryで集計
データの用意
まずはBigQueryにデータを入れていきます
データセット作成
「データセットを作成」クリック
データセットIDを入力
プロジェクトに、空のデータセットが作成されました
テーブル作成
「テーブルを作成」をクリック。データソースとしてCSVファイルをアップロード
CSVファイルが読み込まれ、テーブルが作成されました
SQL
現時点でデータは約30,000行
ただ、数が多いのは分析対象であるインナーウェアの「色ごと/サイズごと」で行が分けられているためで、Amazonでは色/サイズが違っても「1商品扱い(ひとまとめにレビューされる)」で設定されている場合が多くあります
今回のインナーウェアも、商品によっては30バリエーション以上ある商品もありますが、それも「1商品扱い」となります
今回「1商品扱い」となる条件は以下と設定します
- ブランド名が同一
- 商品名が同一
- レビュー:評価が同一
- レビュー:件数が同一
以上を踏まえ、SQLで商品情報の重複(同じ商品のバリエーション違い)をグルーピングします
SELECT brand_name, product_name, rating, review_count, TRUNC (AVG (price)) price_avg FROM `practice-01-234805.amazon_products.az_innerwear` GROUP BY brand_name, product_name, rating, review_count ORDER BY brand_name, product_name, review_count DESC ;「1商品扱い」でも、価格が違う場合があるので(とてもややこしいですが…)、価格に関してはグルーピングした「平均」を着地とし、TRUNC関数で小数点以下を切り捨てています
「色/サイズ違い」をひとまとめにした結果、約30,000行あったデータが約400行にまとまり、各商品の平均価格が算出できました
▼ Googleデータポータルで可視化
BigQueryで集計したデータを、Googleデータポータルで可視化し、分析していきます
「データポータルで調べる」をクリックGoogleデータポータルにデータが引き継がれます
グラフ選択
分析に適したグラフを選択
ディメンション/指標設定
分析したいディメンションと指標を設定
可視化 結果
今回は各ブランドごとのレビュー数の比較や、価格帯ごとの商品数やレビュー数の比較等を行います
ブランド割合/レビュー投稿数の割合
左の円グラフ「ブランド割合」で見ると、商品全体の半数以上を「wc」というブランドが占めており、次に「ck」というブランドが続きます
さらに、右の円グラフ「レビュー投稿数の割合」では「wc」が7割以上を占めており、このブランドはレビューの獲得にとくに成功していると言えます
ブランド毎の平均価格とレビュー評価
上記は、ブランド毎の以下の値を棒グラフにしたものです
- ブルー棒|平均価格
- レッド棒|平均レビュー評価
「cc」というブランドが高価格でありながら、他のブランドに比べレビューの評価が「3.7」と低めです
高価格であることによるユーザーの期待に、十分に応えられていない可能性がありそうです価格毎の レビュー投稿数と 商品数
上記グラフは
- 左が低価格商品。右に行くほど高価格商品
- ブルー棒|レビューの平均投稿数
- オレンジ線|各価格帯の商品数
となっており、高価格商品になるにつれ(グラフ右に行くにつれ)、レビュー投稿数が多いことが分かります
またグラフ左右を比べると、グラフ左側(低価格帯)は、商品数(オレンジの線)に対し、レビューの平均投稿数(ブルーの棒)が少なめになっています。つまり「高価格の商品ほどレビューが投稿されやすく、低価格の商品はレビューが投稿されずらい」と言えます
高価格の商品の方が低価格商品より熱を持って購入され、レビューに対するモチベーションも高くなるのではないか、と考えることができそうです
総括
約30,000件の商品データを、BigQueryで集計、Googleデータポータルで可視化・分析し、
- wcというブランドがレビューの獲得にとくに成功している
- ccというブランドが、高価格であることの期待に応えられていない可能性がある
- 高価格の商品ほどレビューが投稿されやすい
など、特徴・傾向を把握することができました。それをもって、
- ccブランドの満足度向上に取り組む
- 低価格商品のレビュー獲得手段を検討する
など、次の施策検討に活かすことができるかと考えます
- 投稿日:2019-05-06T01:19:17+09:00
【BigQuery】 商品データを分析・可視化
概要
ECサイトの商品データ約30,000件をBigQueryで集計、Googleデータポータルで可視化・分析し、データの特徴や傾向把握を試みます
対象データ
今回対象とするのは、「Amazonにおけるインナーウェア製品データ」です
上記のように、「商品名/価格(ドル)/ブランド名/レビュー件数..」等のデータが約30,000件入っています
Kaggleにて公開されているので、CSVファイルとしてダウンロードしてきます※実際のデータでは実在のブランド名が使われていますが、この記事内では全て仮名に置き換えています
▼ BigQueryで集計
データの用意
まずはBigQueryにデータを入れていきます
データセット作成
「データセットを作成」クリック
データセットIDを入力
プロジェクトに、空のデータセットが作成されました
テーブル作成
「テーブルを作成」をクリック。データソースとしてCSVファイルをアップロード
CSVファイルが読み込まれ、テーブルが作成されました
SQL
現時点でデータは約30,000行
ただ、数が多いのは分析対象であるインナーウェアの「色ごと/サイズごと」で行が分けられているためで、Amazonでは色/サイズが違っても「1商品扱い(ひとまとめにレビューされる)」で設定されている場合が多くあります
今回のインナーウェアも、商品によっては30バリエーション以上ある商品もありますが、それも「1商品扱い」となります
今回「1商品扱い」となる条件は以下と設定します
- ブランド名が同一
- 商品名が同一
- レビュー:評価が同一
- レビュー:件数が同一
以上を踏まえ、SQLで商品情報の重複(同じ商品のバリエーション違い)をグルーピングします
SELECT brand_name, product_name, rating, review_count, TRUNC (AVG (price)) price_avg FROM `practice-01-234805.amazon_products.az_innerwear` GROUP BY brand_name, product_name, rating, review_count ORDER BY brand_name, product_name, review_count DESC ;「1商品扱い」でも、価格が違う場合があるので(とてもややこしいですが…)、価格に関してはグルーピングした「平均」を着地とし、TRUNC関数で小数点以下を切り捨てています
「色/サイズ違い」をひとまとめにした結果、約30,000行あったデータが約400行にまとまり、各商品の平均価格が算出できました
▼ Googleデータポータルで可視化
BigQueryで集計したデータを、Googleデータポータルで可視化し、分析していきます
「データポータルで調べる」をクリックGoogleデータポータルにデータが引き継がれます
グラフ選択
分析に適したグラフを選択
ディメンション/指標設定
分析したいディメンションと指標を設定
可視化 結果
今回は各ブランドごとのレビュー数の比較や、価格帯ごとの商品数やレビュー数の比較等を行います
ブランド割合/レビュー投稿数の割合
左の円グラフ「ブランド割合」で見ると、商品全体の半数以上を「wc」というブランドが占めており、次に「ck」というブランドが続きます
さらに、右の円グラフ「レビュー投稿数の割合」では「wc」が7割以上を占めており、このブランドはレビューの獲得にとくに成功していると言えます
ブランド毎の平均価格とレビュー評価
上記は、ブランド毎の以下の値を棒グラフにしたものです
- ブルー棒|平均価格
- レッド棒|平均レビュー評価
「cc」というブランドが高価格でありながら、他のブランドに比べレビューの評価が「3.7」と低めです
高価格であることによるユーザーの期待に、十分に応えられていない可能性がありそうです価格毎の レビュー投稿数と 商品数
上記グラフは
- 左が低価格商品。右に行くほど高価格商品
- ブルー棒|レビューの平均投稿数
- オレンジ線|各価格帯の商品数
となっており、高価格商品になるにつれ(グラフ右に行くにつれ)、レビュー投稿数が多いことが分かります
またグラフ左右を比べると、グラフ左側(低価格帯)は、商品数(オレンジの線)に対し、レビューの平均投稿数(ブルーの棒)が少なめになっています。つまり「高価格の商品ほどレビューが投稿されやすく、低価格の商品はレビューが投稿されずらい」と言えます
高価格の商品の方が低価格商品より熱を持って購入され、レビューに対するモチベーションも高くなるのではないか、と考えることができそうです
総括
約30,000件の商品データを、BigQueryで集計、Googleデータポータルで可視化・分析し、
- wcというブランドがレビューの獲得にとくに成功している
- ccというブランドが、高価格であることの期待に応えられていない可能性がある
- 高価格の商品ほどレビューが投稿されやすい
など、特徴・傾向を把握することができました。それをもって、
- ccブランドの満足度向上に取り組む
- 低価格商品のレビュー獲得手段を検討する
など、次の施策検討に活かすことができるかと考えます