GraphQL では容易にサーバーに負荷をかけるクエリを書けてしまいます。この発表では、そうした悪意あるクエリから GraphQL API を守る手法を紹介します。
本発表の内容は以下のブログ記事でも詳しく解説しています。 https://yigarashi.hatenablog.com/entry/graphql-query-analysis
ϖύϘɾͯͳٕज़େձZJHBSBTIJ(SBQI2-"1*Λѱҙ͋ΔΫΤϦ͔ΒकΔख๏
View Slide
(SBQI2-
ಋೖ(SBQI2-"1*ͷͨΊͷΫΤϦݴޠͱΫΤϦʹԠͨ͡σʔλΛฦ͢ϥϯλΠϜ
ಋೖ(SBQI2-"1*ͷͨΊͷΫΤϦݴޠͱΫΤϦʹԠͨ͡σʔλΛฦ͢ϥϯλΠϜΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ
ಋೖ(SBQI2-"1*ͷͨΊͷΫΤϦݴޠͱΫΤϦʹԠͨ͡σʔλΛฦ͢ϥϯλΠϜΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{me {nameinterests}}ΫΤϦ
ಋೖ(SBQI2-"1*ͷͨΊͷΫΤϦݴޠͱΫΤϦʹԠͨ͡σʔλΛฦ͢ϥϯλΠϜΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{me {nameinterests}}ΫΤϦ{"me": {"name": "yigarashi","interests": ["ϓϩδΣΫτϚωδϝϯτ","GraphQL","ϓϩάϥϛϯάݴޠཧ",]}}ฦΓʢ+40/ʣ
ಋೖ(SBQI2-"1*ͷͨΊͷΫΤϦݴޠͱΫΤϦʹԠͨ͡σʔλΛฦ͢ϥϯλΠϜΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{me {nameinterests}}ΫΤϦ{"me": {"name": "yigarashi","interests": ["ϓϩδΣΫτϚωδϝϯτ","GraphQL","ϓϩάϥϛϯάݴޠཧ",]}}ฦΓʢ+40/ʣΫΤϦͱಉ͡ܗͷ+40/͕ฦ͞ΕΔ
ಋೖ(SBQI2-͏গ͠ෳࡶͳྫΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ
ಋೖ(SBQI2-͏গ͠ෳࡶͳྫΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 1) {namecities(first: 2) {name}}}ΫΤϦ
ಋೖ(SBQI2-͏গ͠ෳࡶͳྫΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 1) {namecities(first: 2) {name}}}ΫΤϦҾΛड͚औΔ͜ͱ͕Ͱ͖ΔɻpSTU42-Ͱݴ͏MJNJU
ಋೖ(SBQI2-͏গ͠ෳࡶͳྫΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 1) {namecities(first: 2) {name}}}ΫΤϦ{"countries": [{"name": "ຊ","cities": [{ "name": "ژࢢ" },{ "name": "৽॓۠" },]},]}ฦΓʢ+40/ʣҾΛड͚औΔ͜ͱ͕Ͱ͖ΔɻpSTU42-Ͱݴ͏MJNJU
ύϫϑϧ
ѱҙ͋Δਓ͕͏ͱʜʜ
ѱҙ͋ΔΫΤϦ ΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ
ѱҙ͋ΔΫΤϦ ΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 100) {namecities(first: 100) {namestreets(first: 1000) {name}}}}ΫΤϦ
ѱҙ͋ΔΫΤϦ ΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 100) {namecities(first: 100) {namestreets(first: 1000) {name}}}}ΫΤϦººສϊʔυ
ѱҙ͋ΔΫΤϦ ΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 100) {cities(first: 100) {superComplexStatistics}}}ΫΤϦ
ѱҙ͋ΔΫΤϦ ΫϥΠΞϯταʔόʔʢϥϯλΠϜʣ{countries(first: 100) {cities(first: 100) {superComplexStatistics}}}ΫΤϦඇৗʹॏ͍ܭࢉΛճ
ࠓͷςʔϚ(SBQI2-"1*Λѱҙ͋ΔΫΤϦʢʹҙਤతʹෛՙΛ͔͚ΔΫΤϦʣ͔ΒकΔ
ࠓͷςʔϚ(SBQI2-"1*Λѱҙ͋ΔΫΤϦʢʹҙਤతʹෛՙΛ͔͚ΔΫΤϦʣ͔ΒकΔయܕతͳෛՙʢσʔλͷऔಘݩ3%#ͱԾఆ͢ΔʣσʔλྔܭࢉྔجຊతͳΞΠσΟΞʮΫΤϦΛ੩తղੳͯ͠ෛՙͷ͕ͳ͍͜ͱΛ֬ೝ࣮ͯ͠ߦ͢Δʯ
۩ମతͳख๏ϗϫΠτϦετʹΑΔ੍ݶDPNQMFYJUZʹΑΔ੍ݶ
ϗϫΠτϦετʹΑΔ੍ݶαʔόʔ͕ड͚͚ΔΫΤϦΛϗϫΠτϦετͱ͓ͯ࣋ͬͯ͘͠ɻϦΫΤετ͞ΕͨΫΤϦ͕ϗϫΠτϦετʹҰக͢Δ߹͚࣮ͩߦ͢ΔαʔόʔʢϥϯλΠϜʣΫϥΠΞϯτ
ϗϫΠτϦετʹΑΔ੍ݶαʔόʔ͕ड͚͚ΔΫΤϦΛϗϫΠτϦετͱ͓ͯ࣋ͬͯ͘͠ɻϦΫΤετ͞ΕͨΫΤϦ͕ϗϫΠτϦετʹҰக͢Δ߹͚࣮ͩߦ͢ΔαʔόʔʢϥϯλΠϜʣ{countries(first: 10) {name}}ϗϫΠτϦετʜ ʜΫϥΠΞϯτ
ϗϫΠτϦετʹΑΔ੍ݶαʔόʔ͕ड͚͚ΔΫΤϦΛϗϫΠτϦετͱ͓ͯ࣋ͬͯ͘͠ɻϦΫΤετ͞ΕͨΫΤϦ͕ϗϫΠτϦετʹҰக͢Δ߹͚࣮ͩߦ͢ΔαʔόʔʢϥϯλΠϜʣ{countries(first: 10) {name}}ϗϫΠτϦετʜ ʜΫϥΠΞϯτ{countries(first: 10) {name}}
ϗϫΠτϦετʹΑΔ੍ݶαʔόʔ͕ड͚͚ΔΫΤϦΛϗϫΠτϦετͱ͓ͯ࣋ͬͯ͘͠ɻϦΫΤετ͞ΕͨΫΤϦ͕ϗϫΠτϦετʹҰக͢Δ߹͚࣮ͩߦ͢ΔαʔόʔʢϥϯλΠϜʣ{countries(first: 10) {name}}ϗϫΠτϦετʜ ʜΫϥΠΞϯτ{countries(first: 10) {namepopulation}}
ϗϫΠτϦετʹΑΔ੍ݶϝϦοτಋೖ͕༰қʢΫΤϦ͕จࣈྻͱͯ͠Ұக͢Δ͔֬ೝ͢Δ͚ͩͰྑ͍ʣޮՌ͕ߴ͍ʢຊʹ͏ΫΤϦͷΈϗϫΠτϦετͱͯ͠ڐՄ͢ΔͨΊʣσϝϦοτϗϫΠτϦετͷϝϯςφϯείετެ։"1*εςʔΫϗϧμʔͷҧ͏ΫϥΠΞϯτͰ͍ͮΒ͍૯ධؔ͢Δ։ൃऀɾΫϥΠΞϯτ͕গͳ͍߹ʹ͔ͳΓ༗ޮ
DPNQMFYJUZʹΑΔ੍ݶΫΤϦͷෛՙʹൺྫͯ͠େ͖͘ͳΔʢDPNQMFYJUZʣΛܭࢉ͢Δɻͦͷ͕ᮢΛ͑ͨ߹࣮ߦ͠ͳ͍
DPNQMFYJUZʹΑΔ੍ݶΫΤϦͷෛՙʹൺྫͯ͠େ͖͘ͳΔʢDPNQMFYJUZʣΛܭࢉ͢Δɻͦͷ͕ᮢΛ͑ͨ߹࣮ߦ͠ͳ͍యܕతͳෛՙʹ͍ͭͯDPNQMFYJUZͷྫΛݟ͍ͯ͘σʔλྔܭࢉྔ%#ΞΫηεճʢҙʣDPNQMFYJUZͷܭࢉํ๏ແʹߟ͑ΒΕΔɻࠓࣔ͢ͷҰྫ
ྫϊʔυʹൺྫ͢ΔDPNQMFYJUZ
ྫϊʔυʹൺྫ͢ΔDPNQMFYJUZ{countries(first: 50) {namecities(first: 100) {name}}}
ྫϊʔυʹൺྫ͢ΔDPNQMFYJUZϊʔυDPVOUSJFTºDJUJFTOPEFT{countries(first: 50) {namecities(first: 100) {name}}}
ྫϊʔυʹൺྫ͢ΔDPNQMFYJUZϊʔυDPVOUSJFTºDJUJFTOPEFT͜Ε͕ᮢҎԼͳΒ࣮ߦ͢Δ{countries(first: 50) {namecities(first: 100) {name}}}
ྫϊʔυʹൺྫ͢ΔDPNQMFYJUZϊʔυDPVOUSJFTºDJUJFTOPEFT͜Ε͕ᮢҎԼͳΒ࣮ߦ͢Δ{countries(first: 50) {namecities(first: 100) {name}}}ࢀߟ(JU)VC(SBQI2-"1*Wͷ/PEFMJNJUϊʔυ ·ͰϦετͷऔಘͰҾʹpSTU͔MBTU͕ඞਢͰҎ
ྫܭࢉίετʹൺྫ͢ΔDPNQMFYJUZ
ྫܭࢉίετʹൺྫ͢ΔDPNQMFYJUZtype City {namesuperComplexStatistics @cost(n: 10)}
ྫܭࢉίετʹൺྫ͢ΔDPNQMFYJUZtype City {namesuperComplexStatistics @cost(n: 10)}(SBQI2-ͷEJSFDUJWFΛར༻ͯ͠ɺܕఆٛʢεΩʔϚʣͷଆͰॏ͍ܭࢉʹίετΛ͚ͭΔɻαʔόʔ͜ͷใΛࢀরͯ͠DPNQMFYJUZΛܭࢉ͢Δ
ྫܭࢉίετʹൺྫ͢ΔDPNQMFYJUZtype City {namesuperComplexStatistics @cost(n: 10)}(SBQI2-ͷEJSFDUJWFΛར༻ͯ͠ɺܕఆٛʢεΩʔϚʣͷଆͰॏ͍ܭࢉʹίετΛ͚ͭΔɻαʔόʔ͜ͷใΛࢀরͯ͠DPNQMFYJUZΛܭࢉ͢Δ{countries(first: 100) {cities(first: 100) {superComplexStatistics}}}ΫΤϦ
ྫܭࢉίετʹൺྫ͢ΔDPNQMFYJUZtype City {namesuperComplexStatistics @cost(n: 10)}(SBQI2-ͷEJSFDUJWFΛར༻ͯ͠ɺܕఆٛʢεΩʔϚʣͷଆͰॏ͍ܭࢉʹίετΛ͚ͭΔɻαʔόʔ͜ͷใΛࢀরͯ͠DPNQMFYJUZΛܭࢉ͢Δ{countries(first: 100) {cities(first: 100) {superComplexStatistics}}}ܭࢉίετ ºDJUJFTºDPTU ΫΤϦ
ྫܭࢉίετʹൺྫ͢ΔDPNQMFYJUZtype City {namesuperComplexStatistics @cost(n: 10)}(SBQI2-ͷEJSFDUJWFΛར༻ͯ͠ɺܕఆٛʢεΩʔϚʣͷଆͰॏ͍ܭࢉʹίετΛ͚ͭΔɻαʔόʔ͜ͷใΛࢀরͯ͠DPNQMFYJUZΛܭࢉ͢Δ{countries(first: 100) {cities(first: 100) {superComplexStatistics}}}ܭࢉίετ ºDJUJFTºDPTU ΫΤϦ%#ΞΫηεճશ͘ಉ͡ΞΠσΟΞͰDPNQMFYJUZΛઃܭͰ͖Δɻ%#ΞΫηε͕ൃੜ͢ΔϑΟʔϧυʹDPTUΛ͚ͭΕɺ%#ΞΫηεճʹൺྫͯ͠DPNQMFYJUZ͕૿Ճ͢ΔΑ͏ʹͰ͖Δɻ
࣮(SBQI2-Ͱྑ͘ΘΕΔݴޠͰϥΠϒϥϦͷαϙʔτ͕͋Δ+BWB4DSJQUHSBQIRMDPTUBOBMZTJTͳͲ(PHRMHFO͕αϙʔτ͍ͯ͠Δαϙʔτͷͳ͍ݴޠͰͲ͏͢Δ͔ΫΤϦղੳ͚ͩϚΠΫϩαʔϏεͱͯ͠Γग़ͯ͠ผݴޠΛ͏ࣗલͰ࣮͢Δ
ମݧஊͱ͋ΔαʔϏεͰϑϧεΫϥονͰΫΤϦղੳΛ࣮ʢ1FSMͩͬͨͷͰʜʣεςʔΫϗϧμʔͷҧ͏ΫϥΠΞϯτ͕༧͞ΕͨͷͰϗϫΠτϦετʹΑΔ੍ݶݟૹͬͨQBSTFͱFYFDVUFͷؒʹDPNQMFYJUZʹΑΔ੍ݶΛࠐΜͩϕʔεϊʔυʹΑΔ੍ݶશ݅औಘ͢ΔϑΟʔϧυ%#ΞΫηε͕ൃੜ͢ΔϑΟʔϧυʹߴΊͷίετΛ͚ͭΔᮢ௨ৗར༻Λ્͠ͳ͍େ͖ΊͷʹઃఆڥมͰᮢΛઃఆͰ͖ΔΑ͏ʹͯ͠ૉૣ͘ରॲՄೳʹ
ݱঢ়ͷ՝DPNQMFYJUZͷϕετϓϥΫςΟεཱ͕֬͞Ε͍ͯͳ͍ࠓճϊʔυɾܭࢉίετɾ%#ΞΫηεʹணͯٞ͠Λ͕ͨ͠ɺͦͦ͜͜·Ͱ౿ΈࠐΜͰ͍ٞͯ͠Δࢿྉ͕গͳ͍ޙΖʹ%#Ҏ֎͕͍ΔέʔεͳͲଞʹ͋Γͦ͏ੈͷதͷϥΠϒϥϦDPNQMFYJUZ͕ͻͱͭͷέʔεΛް͘αϙʔτ͍ͯ͠Δϊʔυɾܭࢉίετͱ͍ͬͨෳͷईΛѻ͍ͮΒ͍ํͳ͘ͻͱͭͷDPNQMFYJUZʹෳͷईΛԡ͠ࠐΉ͜ͱ+BWB4DSJQUͷHSBQIRMDPTUBOBMZTJTͰ࣮ݱՄೳͳ͜ͱΛ֬ೝ
·ͱΊ(SBQI2-ͰҙਤతʹෛՙΛ͔͚ΔΫΤϦΛ༰қʹهड़Ͱ͖ΔͭͷӴखஈΛհͨ͠ϗϫΠτϦετʹΑΔ੍ݶDPNQMFYJUZʹΑΔ੍ݶᘳͳӴඞͣ͠ඞཁͳ͍ϦεΫͱରࡦͷશମ૾Λݟ͠ཁ݅ʹ͋ͬͨίεύͷྑ͍ํΛऔΔϒϩάهࣄ൛ʮ(SBQI2-"1*Λѱҙ͋ΔΫΤϦ͔ΒकΔख๏ʯIUUQTZJHBSBTIJIBUFOBCMPHDPNFOUSZHSBQIRMRVFSZBOBMZTJT