ã51CTO.comå¿«è¯ãä½ä¸ºæä¸ºæµè¡çæ¥è¯¢è¯è¨ä¹ä¸ï¼GraphQLè½ç¶è½å¤æ¯æåå»ºçµæ´»çAPIï¼ä½æ¯å®ä¹å®¹ææ¾è¿ãçè³ç»åºç¨ç¨åºæå¡å¨å¸¦æ¥åç§æ¶æçæ¥è¯¢ãä¸äºå¸¸è§çGraphQLæ¼æ´å¾å¾ä¼å¨ä¸è´æ§è¯ä¼°å缺é·ç¼è§£çæ¹é¢åä¸åç§å®å ¨éæ£ã卿¬æä¸ï¼æä»¬å°æ·±å ¥åæ¨æ¢è®¨GraphQLçåç§å¸¸è§æ¼æ´ï¼ä»¥åé使¤ç±»é£é©çä¼ç§å®è·µã
ä»ä¹æ¯GraphQL?
ä½ä¸ºä¸ç§æå¡å¨ç«¯è¿è¡æ¶(runtime)çAPIæ¥è¯¢è¯è¨ï¼GraphQLè½å¤ä¼å è¿å客æ·ç«¯è¯·æ±çæ°æ®ã该è¯è¨ä¸ä½è½å¤è®©APIåå¾è½»å·§ãçµæ´»ï¼èä¸å¯¹äºå¼å人åååå好䏿¹ä¾¿ä»ä»¬è¿è¡å¿«éå¼åãèä½ä¸ºREST APIæ¡æ¶çæ¿ä»£æ¹æ¡ï¼GraphQLå 许å¼åå¢éå¨å个æ¥å£çè°ç¨ä¸ï¼å建å¯è®¿é®æ¥èªå¤ä¸ªæ°æ®æºç请æ±ã该è¯è¨å¯ä»¥è¢«é¨ç½²å°éæå¼åç¯å¢(IDE)ä¸ï¼å¹¶æä¾æè¿°ç¨æ·è¯¥å¦ä½è¯·æ±æ°æ®çè¯æ³ãå¯ä»¥è¯´ï¼GraphQLæ¢æä¾äºä¸ä¸ªå¯é¢æµè¿è¡çæ¡æ¶ï¼åå 许å¼å人åèªè¡éæ©æå»ºAPIçæ¹æ³ã
GraphQLç常è§å®å ¨é®ç
APIæ»å»æ®éå?
éçAPIæ®é被使ç¨ï¼é对å®çæ»å»å°è¯å¨æ°éä¸ä¹å¨æç»å¢å ãè¿äºæ»å»é常ä¾èµäºéè¿åºç¨ç¨åºçç¼ç¨æ¥å£ï¼å»èªå¨åæ§è¡åç§æ¶ææä½ãæ ¹æ®Wallarm.comçä¸ä»½ç»è®¡æ¥åï¼æªè³2019å¹´ï¼æ¶æèªå¨åæ»å»ä¸»æºãåå ¶ç½ç»å·²å äºèç½ç20%ãè¿ä½¿å¾ä¿æ¤APIæä¸ºåºç¨ç¨åºå®å ¨æªæ½çä¸ä¸ªå ³é®ç¯èã
æ¯å¦æç®åGraphQLå®å ¨æ§çå·¥å ·?
ç®åï¼ä¸çæå¤ç§å¼æºç项ç®ï¼å¯ä»¥ç®åGraphQL APIçå建å管çãå ¶ä¸å æ¬ï¼Apollo clientãOffixãGraphbackå OpenAPI-to-GraphQLã
GraphQLå¦ä½å¤ç身份éªè¯åææ?
ç±äºGraphQLæ¯ä¸ç§æå¡å¨ç«¯è¿è¡æ¶æ¥è¯¢è¯è¨ï¼å æ¤å®å¹¶ä¸å¤çææçé»è¾ãä¸è¿ï¼è¯¥å¹³å°å 许å¼å人åï¼å¨å客æ·ç«¯å ¬å¼APIä¹åï¼å¨ä¸å¡é»è¾å±ä¸å®æ½èº«ä»½éªè¯åææçæ£æ¥ã
GraphQLçå ·ä½å®å ¨æ§é®é¢
ååçå ¶ä¸°å¯çå¹³å°åè½ï¼ä»¥åè½å¤ç®åAPIæ¥è¯¢çå建è¿ç¨ï¼GraphQL已被èªä¸ºç°ä»£åºç¨å¼åææ¯æ çå ³é®ç»ä»¶ãè为äºåå©ä¼ä¸åå°GraphQL APIçæ»å»é¢ï¼æä»¬å¯ä»¥éè¿å¦ä¸æ¹é¢æ¥ç®¡æ§GraphQLå¹³å°çåºæå®å ¨é®é¢ï¼
èªå®ä¹æ éçéªè¯ä¸è¶³
å¨ä½¿ç¨GraphQLæ¶ï¼åå§æ°æ®å¾å¾æ¯ç±æ éç±»å(scalar type)表示çãGraphQL APIéå¸¸æ¯æäºç§åºæ¬çæ éæ°æ®ç±»åï¼å³ï¼IntãFloatãBooleanãIDåStringãè½ç¶è¿ä¸ªåºæ¬éå对äºç®åçAPIæ¥è¯´å·²ç»è¶³å¤äºï¼ä½æ¯GraphQLä¹å 许å¼å人åéå¯¹ç¹æ®çåå§æ°æ®APIç±»åéæ±ï¼èªè¡å建æ éç±»åãå½ç¶ï¼å¼å人åéè¦é对æ¤ç±»é ç½®ï¼é¢å¤å°å¢å ç¨æ·è¾å ¥çéªè¯ã以忏 ççè¿ç¨ãç¸åï¼å¦ææªè½å®ç°æ¤ç±»åè½ï¼åä¼å±åå°GraphQLæ éç±»åçå®å ¨æ§ã
REST代çå å½APIæ»å»åªä»
å¨è°æ´ç°æçAPI以ä¾GraphQL客æ·ç«¯è°ç¨æ¶ï¼å¼å人åé常ä¼å°GraphQLå®ç°ä¸ºï¼å¨å é¨RESTæ¡æ¶ä¹ä¸çä¸ä¸ªç¦ä»£çå±ã妿卿²¡æå åèèå°å®å ¨å ç´ çæ åµä¸å®æ½æ¤ç±»è½¬æ¢ï¼é£ä¹æ¶æç¨æ·å°±å¯ä»¥ä»»æä¿®æ¹API请æ±ä¸ææå®çè·¯å¾æåæ°ãèä¿®æ¹åç请æ±å¨è§£æå°å端APIæ¶ï¼æ»å»è 便å¯ä»¥å®æ½è·¨ç«è¯·æ±ä¼ªé ( cross-site request forgeryï¼CSRF)äºã
ææç¼ºé·
GraphQLå°é ç½®ææå身份éªè¯çæ£æ¥è´£ä»»ï¼çç»äºæç»å®ç°è ãå³ï¼GraphQL API卿¥è¯¢çº§å«çè§£æå¨ã以åå è½½éå æ°æ®çè§£æå¨ä¸ï¼éè¦å å«å¤é¡¹æææ£æ¥ãè彿æç±æ¥è¯¢çº§è§£æå¨ç´æ¥å¤çæ¶ï¼ä»»ä½æªç»æ£æ¥çAPIå®ä¾é½ä¼æ´é²åæ»å»é¢ãèä¸ï¼éçAPI模å¼å¤ææ§çå¢å ï¼æ¤ç±»è¢«æ»å»è å©ç¨çæ¼æ´é£é©ä¹ä¼éä¹å¢å ã
èªçæ¥è¯¢(Introspection Queries)å¯è½ä¼æ´é²æææ°æ®
å¼å人å为äºå»å®ç°é£äºæ æ³å ¬å¼è®¿é®çâéèâAPI端ç¹ï¼ä¼å¯ç¨GraphQLæå¡å¨ä¹é´çAPI端ç¹éä¿¡ï¼æéè¿éèç管çåè½æ¥å®ç°ãå ¶ä¸ï¼GraphQLå å«äºä¸ä¸ªèªçåè½ï¼å¯ä»¥å¨æ²¡æé彿æçæ åµä¸ï¼è½»æ¾å°è®¿é®å个端ç¹ãç±äºèªçåè½å 许客æ·ç«¯è®¿é®æå ³GraphQLæ¶æçä¿¡æ¯ï¼å æ¤ä¸æ¦ææ»å»åçï¼èªçæ¥è¯¢å°±å¯ä»¥è¢«ç¨äºè®¿é®APIçç¸å ³é ç½®ã以åå ¶ä»å®¢æ·ç«¯çç§æä¿¡æ¯ã
éçéå¶é¾ä»¥å®æ½
仿¬è´¨ä¸è¯´ï¼GraphQL APIæ¯æ¯è¾å¤æçãå®çæ¯ä¸ä¸ªæ¥è¯¢é½ä¼æ¶åå°å¤é¡¹æä½ï¼å¹¶ä¸ä¼æ¶è大éçæå¡å¨èµæºãå æ¤ï¼å é éå¶æ¥æ¶å°çHTTPè¯·æ±æ°éï¼å¹¶ä½¿ç¨é»è®¤çéçéå¶çç¥æ¯ä¸å¤çã妿䏤ç§å¯¹è±¡ç±»åä¹é´åå¨çæç§å¾ªç¯å ³ç³»ï¼é£ä¹æ»å»è å°±å¯ä»¥éè¿å建åç§æ»¥ç¨æ¥è¯¢(abusive queries)ï¼ä»è让æ¥è¯¢æ¬èº«åå¾å¼å¸¸å¤æã以æ¤äº§ççç¼æï¼è½å¤å¯¹GraphQLåºç¨åèµ·æç»æå¡å¼(DoS)çæ»å»ã
常è§çGraphQLæ¼æ´
ä¸é¢ï¼æä»¬æ¥è¿ä¸æ¥è®¨è®ºGraphQLæåªäºå¸¸è§çæ¼æ´ï¼å¯è¢«æ¶ææ»å»è å¨APIå±é¢å©ç¨ã
GraphQLæ¹å¤çæ»å»
GraphQLæ¡æ¶è½å¤æ¯æèªçæ¥è¯¢çæ¹å¤çï¼å³ï¼è½å¤å¨ä¸æ¬¡æ§è°ç¨ä¸ï¼åå端APIåéå¤ä¸ªè¯·æ±ãç±äºåå°äºè¯·æ±ä¸æå¡å¨ä¹é´çå¾è¿æ¬¡æ°ï¼å æ¤è¿å¯¹äºåå°API请æ±çå¼éé常å®ç¨ãä¸è¿ï¼æ»å»è ä¹å¯ä»¥ä½¿ç¨æ¥è¯¢çæ¹å¤çåè½ï¼éè¿åå¤ä»APIæå¡å¨ãææ°æ®åºå¤å è½½æ°æ®ï¼æ¥ç¼æåç§å¿«éä¸é¾ä»¥è¢«æ£æµå°çæ´åæ»å»ã
以ä¸å ¸å示ä¾å±ç¤ºäºï¼å¨æç´¢æ°åè®°å½å¯¹è±¡æ è¯(Digital Record Object Identificationï¼DROID)对象çä¸åå®ä¾æ¶ï¼è¿è¡GraphQLæ¹å¤çæ¥è¯¢ç代ç ï¼
query { droid(id: "2000"ï¼{ name } second:droid(id: "2001"ï¼{ name } third:droid(id: "2002"ï¼{ name } }
èæ»å»è å¯ä»¥éè¿å¶é ä¸äºç½ç»è¯·æ±ï¼æ¥æä¸¾APIæå¡å¨ä¸çæ¯ä¸ä¸ªdroid对象ãè¿å°±å¯è½ä¼å¯¼è´API级å«çDoSæ»å»ãæ´åç ´è§£ç§å¯æ°æ®ãç»è¿è¯·æ±çéçéå¶ã以å对象æä¸¾çå®å ¨é®é¢ã
GraphQLæ³¨å ¥æ»å»
GraphQL APIé常ä¸ä½ä¸ºæ°æ®æºçæ°æ®åºç®¡çç³»ç»ç¸è¿æ¥ãAPIå端çResolver卿¶å°è¯·æ±åï¼ä¼æ ¹æ®æä½éæ¥åºåæ¥è¯¢ãå¨Resolveræ¥è¯¢æ°æ®åºæ¶ï¼å¦æå ¶æä½æ¶åå°æ°æ®çæåï¼é£ä¹å°±ä¼ç´æ¥æ§è¡ç¸åºçè·åæä½ãå¯è§ï¼å¦ææ¥èªAPI客æ·ç«¯çæ°æ®ï¼å¨æªè¢«é彿¸ ççæ åµä¸ï¼æ§è¡ä»»ä½åä¿¡çæä½ï¼é£ä¹é»å®¢å°±å¯ä»¥éè¿ç¼æSQL/NoSQLï¼æ¥å®æ½æ³¨å ¥æ»å»ãåæ ·ï¼å¦æå¯¹è¾å ¥çæ¸ çä¸å¤å åï¼æ»å»è è¿ä¼æ§è¡è¯¸å¦LDAPæ³¨å ¥ã以åå½ä»¤æ³¨å ¥çå ¶ä»å½¢å¼çæ³¨å ¥æ»å»ã
GraphQL CSRFæ»å»
è·¨ç«è¯·æ±ä¼ªé (CSRF)æ»å»æ¯æï¼å¨åæ³ç¨æ·ä¸ç¥æ æ¶ï¼å¼ºè¿«Webæå¡å¨è¿è¡é£äºä¸å¿ è¦çæä½ãå½åå¨CSRFæ¼æ´æ¶ï¼æ»å»è ä¼å¨å½åç»å½ç¨æ·çä¸ä¸æï¼åéç»è¿èº«ä»½éªè¯ç请æ±ãèGraphQLç±»åçåºç¨ææåå°CSRFæ»å»ï¼æ¯ç«API卿¥æ¶æµè§å¨çè¯·æ±æ¶ï¼ä¼èªå¨æ¥åææçcookie(å ¶ä¸å°±å æ¬äºä¼è¯cookie)ã
ç®åï¼ä¸»è¦æä¸¤ç§ç±»åçGraphQL CSRFæ»å»ï¼åºäºPostååºäºGetçCSRFãç±äºGraphQL使ç¨å¤ä¸ªAPI屿¥è½¬æ¢ä¼ å ¥ç夿 ¼å¼è¯·æ±ï¼èä¸è½å¤å½±åå°GraphQLåºç¨çç¶æï¼å æ¤å¤§å¤æ°CSRFæ»å»é常以POST请æ±ä¸ºç®æ ãé常ï¼è®¸å¤å¼å人åä¼åªæ¥å设置为application/jsonçContent-Typeæ 头ãä¾å¦ï¼ä»¥ä¸POST请æ±å¯ç¨äºååºææçGraphQLæ¥è¯¢ï¼
POST /GraphQLHTTP/1.1 Host: redacted Connection: close Content-Length: 100 accept: */* User-Agent: ... content-type: application/json Referer: https://redacted/ Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Cookie: ... {"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
æå¡å¨å¯ä»¥å°æ¤è¯·æ±ä½ä¸ºform-urlencoded POST请æ±äºä»¥æ¥åï¼
POST /GraphQLHTTP/1.1 Host: redacted Connection: close Content-Length: 72 accept: */* User-Agent: Mozilla/5.0ï¼Macintosh; Intel Mac OS X 11_2_2ï¼AppleWebKit/537.36ï¼KHTML, like Geckoï¼Chrome/89.0.4389.82 Safari/537.36 Content-Type: application/x-www-form-urlencoded Referer: https://redacted Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Cookie: ... query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
èæç»éªçæ»å»è åå¯ä»¥ä½¿ç¨èªå¨åæ«æå·¥å ·ï¼å°å ¶è½¬æ¢ä¸ºCSRFçæ»å»æ¥å£ï¼
弥补GraphQLæ¼æ´çæ¸ å
ä¸é¢ï¼æä»¬å°ä»¥æ¸ åçå½¢å¼ï¼ç»åºä¸äºä¸GraphQLå®å ¨æå ³çä¼ç§å®è·µã
鲿¢GraphQLæ³¨å ¥æ»å»
对äºé£äºç±LDAPãORMs/SQL/NoSQLæXMLçè¾ å©è§£æå¨ï¼æ¥å¤çè¾å ¥ä¿¡æ¯çåºç¨èè¨ï¼æä»¬å»ºè®®å¼å人ååå°å¦ä¸æ¹é¢ï¼
éæ©è¯¸å¦åæ°åè¯å¥çè½å¤æä¾å®å ¨APIçåºã
æ ¹æ®æéç¨çè§£æå¨çæä½³å®è·µï¼å¯¹è¾å ¥è¿è¡è½¬ä¹æç¼ç ã
éµå¾ªæé模åçææ¡£ï¼ä»¥æ£ç¡®çæ¹å¼ä½¿ç¨è¯¥å·¥å ·ãæ¯ç«ï¼å¤§å¤æ°è¯è¨åæ¡æ¶é½å ç½®äºç¼ç /转ä¹åè½ï¼å æ¤äºè§£å®ä»¬çæ ¸å¿åè½ï¼å¹¶éæ©éåçç¨ä¾æ¯é常éè¦çã
é¢é²DoSæ»å»
DoSæ»å»æ¨å¨ä½¿å¾GraphQL APIåæ ¢ãçè³æ æ³ååºæ£å¸¸ç请æ±ã为äºé²å¾¡æ¤ç±»æ»å»ï¼æä»¬åºåå°ï¼
ä¸ºä¼ å ¥çGraphQLæ¥è¯¢å®æ½æ·±åº¦çè§åéå¶(depth limiting)ã
为åºç¡è®¾æ½åAPI屿·»å è¶ æ¶è®¾å®ã
æ§è¡æ¥è¯¢çææ¬åæï¼ä»¥éå¶ä»£ä»·æè´µçæ¥è¯¢ã
对æ¯ä¸ªAPI客æ·ç«¯çä¼ å ¥è¯·æ±ï¼å®æ½éçéå¶ã
GraphQL APIçè®¿é®æ§å¶
为äºä¿æ¤å¯¹GraphQL APIçåç访é®ï¼å¼å人ååºè¯¥åå°ï¼
éªè¯å½åç¨æ·æ¯å¦æææ ¹æ®ä»ä»¬ç请æ±ï¼æ¥çãæ¹åã以åä¿®æ¹æ°æ®ã
对端ç¹åè¾¹ç¼å®æ½æææ§å¶ã
å©ç¨åºäºè§è²çè®¿é®æ§å¶(RBAC)ä¸é´ä»¶ï¼éè¿æ¥è¯¢ååå¼è§£æå¨(mutation solver)ï¼æ¥å¯ç¨è®¿é®æ§å¶ã
å¨å ¬å ±çAPIä¸ç¦ç¨èªçæ¥è¯¢ã
ç¦ç¨GraphiQLä¹ç±»é对GraphQL模å¼çæ¢æ¥å·¥å ·ã
éç¨GraphQL APIå®å ¨å®è·µ
å¼å人åè¿å¯ä»¥ç¨æ¥ä¿æ¤GraphQLå±çå ¶ä»æ¹æ³å æ¬ï¼
对å 许çå符使ç¨ç½ååã
为çªåçè¾å ¥é¢å å®ä¹å¥½å¯¹åºçGraphQL模å¼ã
使ç¨åä¸çå é¨å符ç¼ç æ ¼å¼ï¼æ¥æ£ç¡®å°å¤çUnicodeè¾å ¥ã
æ·»å å页(pagination)ï¼ä»¥éå¶å个请æ±è½å¤ä¸æ¬¡æ§è®¿é®å°çä¿¡æ¯éã
åææ é¢ï¼Best Practices For GraphQL Securityï¼ä½è ï¼Sudip Sengupta
ã51CTOè¯ç¨¿ï¼åä½ç«ç¹è½¬è½½è¯·æ³¨æåæè¯è ååºå¤ä¸º51CTO.comã


