GraphQL Circular References
Referencias circulares de GraphQL
Descripción
GraphQL permite a los clientes solicitar datos específicos, y su flexibilidad puede explotarse para crear consultas complejas o recursivas. Las referencias circulares ocurren cuando un tipo de objeto se refiere a sí mismo directa o indirectamente a través de otros tipos.
Por ejemplo:
query CircularReferences {
user {
friends {
user {
friends {
user {
__typename
}
}
}
}
}
}
Impacto de seguridad de las referencias circulares en GraphQL:
- Denegación de servicio: al enviar una consulta grande con demasiadas referencias anidadas, un atacante puede abrumar al servidor, lo que hace que se ralentice o se bloquee.
- Agotamiento de recursos: el servidor puede quedarse sin recursos de memoria o CPU al procesar la consulta, lo que provoca una degradación del rendimiento o la falta de disponibilidad del servicio.
Recomendación
Para mitigar el riesgo de referencias circulares en GraphQL, puede seguir estas recomendaciones: 1. Limitación de profundidad: Implemente un middleware para verificar la profundidad de la consulta y generar un error si excede el límite. Ejemplo:
class DepthAnalysisMiddleware:
def resolve(self, next, root, info, **args):
if info.operation.selection_set:
depth = 0
for field in info.operation.selection_set.selections:
depth = max(depth, self._get_depth(field))
if depth > 3:
raise Exception('Query depth is too high')
return next(root, info, **args)
def _get_depth(self, field):
if field.selection_set:
return 1 + max(self._get_depth(f) for f in field.selection_set.selections)
return 1
- Detección de referencia circular: Rediseñe el esquema para evitar referencias circulares. Ejemplo de referencia circular:
class User(graphene.ObjectType):
id = graphene.ID()
name = graphene.String()
friends = graphene.List(lambda: User)
def resolve_friends(self, info):
return [User(id=1, name='Alice'), User(id=2, name='Bob')]
Ejemplo de esquema rediseñado:
class FriendProfile(graphene.ObjectType):
id = graphene.ID()
name = graphene.String()
class User(graphene.ObjectType):
id = graphene.ID()
name = graphene.String()
friends = graphene.List(FriendProfile)
def resolve_friends(self, info):
return [FriendProfile(id=1, name='Alice'), FriendProfile(id=2, name='Bob')]
const FriendProfile = new GraphQLObjectType({
name: 'FriendProfile',
fields: {
id: { type: GraphQLID },
name: { type: GraphQLString }
}
});
const User = new GraphQLObjectType({
name: 'User',
fields: {
id: { type: GraphQLID },
name: { type: GraphQLString },
friends: { type: new GraphQLList(FriendProfile) }
}
});
Enlaces
Estándares
- CWE_TOP_25:
- CWE_400
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_4
- REQ_11_3
- OWASP_MASVS_L2:
- MSTG_PLATFORM_2
- OWASP_ASVS_L3:
- V13_4_1
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- CC_9_1
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213