registry now verifies the browser support cookies - to protect its database from being flooded with new persons
Costa Tsaousis committed
Jun 2, 2016 at 16:27 UTC
452901c7a948022ee0a9d895377db0b27aa111bb
3 files changed
+88
-7
src/registry.c
+31
-4
@@ -89,6 +89,7 @@ struct registry {
89
char *hostname;
90
char *registry_to_announce;
91
time_t persons_expiration; // seconds to expire idle persons
92
+ int verify_cookies_redirects;
93
94
size_t max_url_length;
95
size_t max_name_length;
@@ -1011,16 +1012,28 @@ MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *u
1012
#define REGISTRY_STATUS_FAILED "failed"
1013
#define REGISTRY_STATUS_DISABLED "disabled"
1014
1014
-static inline void registry_set_person_cookie(struct web_client *w, PERSON *p) {
1015
+int registry_verify_cookies_redirects(void) {
1016
+ return registry.verify_cookies_redirects;
1017
+}
1018
+
1019
+const char *registry_to_announce(void) {
1020
+ return registry.registry_to_announce;
1021
+}
1022
+
1023
+void registry_set_cookie(struct web_client *w, const char *guid) {
1024
char edate[100];
1025
time_t et = time(NULL) + registry.persons_expiration;
1026
struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
1027
strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
1028
1020
- snprintfz(w->cookie1, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", p->guid, edate);
1029
+ snprintfz(w->cookie1, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", guid, edate);
1030
1031
if(registry.registry_domain && registry.registry_domain[0])
1023
- snprintfz(w->cookie2, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", p->guid, registry.registry_domain, edate);
1032
+ snprintfz(w->cookie2, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", guid, registry.registry_domain, edate);
1033
+}
1034
+
1035
+static inline void registry_set_person_cookie(struct web_client *w, PERSON *p) {
1036
+ registry_set_cookie(w, p->guid);
1037
}
1038
1039
static inline void registry_json_header(struct web_client *w, const char *action, const char *status) {
@@ -1653,9 +1666,23 @@ int registry_init(void) {
1666
registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
1667
registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", hostname));
1668
1669
+ registry.verify_cookies_redirects = config_get_number("registry", "verify browser cookies support max redirects", 2);
1670
+ if(registry.verify_cookies_redirects < 0) {
1671
+ registry.verify_cookies_redirects = 0;
1672
+ config_set_number("registry", "verify browser cookies support max redirects", registry.verify_cookies_redirects);
1673
+ }
1674
+
1675
registry.max_url_length = config_get_number("registry", "max URL length", 1024);
1657
- registry.max_name_length = config_get_number("registry", "max URL name length", 50);
1676
+ if(registry.max_url_length < 10) {
1677
+ registry.max_url_length = 10;
1678
+ config_set_number("registry", "max URL length", registry.max_url_length);
1679
+ }
1680
1681
+ registry.max_name_length = config_get_number("registry", "max URL name length", 50);
1682
+ if(registry.max_name_length < 10) {
1683
+ registry.max_name_length = 10;
1684
+ config_set_number("registry", "max URL name length", registry.max_name_length);
1685
+ }
1686
1687
// initialize entries counters
1688
registry.persons_count = 0;
src/registry.h
+4
@@ -5,6 +5,10 @@
5
6
#define NETDATA_REGISTRY_COOKIE_NAME "netdata_registry_id"
7
8
+extern void registry_set_cookie(struct web_client *w, const char *guid);
9
+extern const char *registry_to_announce(void);
10
+extern int registry_verify_cookies_redirects(void);
11
+
12
extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
13
extern int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
14
extern int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
src/web_client.c
+53
-3
@@ -862,7 +862,7 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
862
{
863
static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
864
hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
865
- hash_to = 0;
865
+ hash_to = 0, hash_redirects = 0;
866
867
if(unlikely(!hash_action)) {
868
hash_action = simple_hash("action");
@@ -877,6 +877,7 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
877
hash_delete_url = simple_hash("delete_url");
878
hash_for = simple_hash("for");
879
hash_to = simple_hash("to");
880
+ hash_redirects = simple_hash("redirects");
881
}
882
883
char person_guid[36 + 1] = "";
@@ -886,9 +887,9 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
887
// FIXME
888
// The browser may send multiple cookies with our id
889
889
- char *cookie = strstr(w->response.data->buffer, " " NETDATA_REGISTRY_COOKIE_NAME "=");
890
+ char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
891
if(cookie)
891
- strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME) + 1], 36);
892
+ strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
893
894
char action = '\0';
895
char *machine_guid = NULL,
@@ -897,6 +898,7 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
898
*search_machine_guid = NULL,
899
*delete_url = NULL,
900
*to_person_guid = NULL;
901
+ int redirects = 0;
902
903
while(url) {
904
char *value = mystrsep(&url, "?&[]");
@@ -918,7 +920,13 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
920
else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
921
else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
922
else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
923
+#ifdef NETDATA_INTERNAL_CHECKS
924
+ else error("unknown registry action '%s'", value);
925
+#endif /* NETDATA_INTERNAL_CHECKS */
926
}
927
+ else if(hash == hash_redirects && !strcmp(name, "redirects"))
928
+ redirects = atoi(value);
929
+
930
else if(hash == hash_machine && !strcmp(name, "machine"))
931
machine_guid = value;
932
@@ -941,6 +949,9 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
949
if(hash == hash_to && !strcmp(name, "to"))
950
to_person_guid = value;
951
}
952
+#ifdef NETDATA_INTERNAL_CHECKS
953
+ else error("unused registry URL parameter '%s' with value '%s'", name, value);
954
+#endif /* NETDATA_INTERNAL_CHECKS */
955
}
956
957
if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
@@ -970,6 +981,45 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
981
982
switch(action) {
983
case 'A':
984
+ if(registry_verify_cookies_redirects() > 0 && (!cookie || !person_guid[0])) {
985
+ buffer_flush(w->response.data);
986
+
987
+ if(redirects > registry_verify_cookies_redirects()) {
988
+ buffer_sprintf(w->response.data, "Your browser does not support cookies");
989
+ return 400;
990
+ }
991
+
992
+ redirects++;
993
+
994
+ char *encoded_url = url_encode(machine_url);
995
+ if(!encoded_url) {
996
+ error("%llu: Cannot URL encode string '%s'", w->id, machine_url);
997
+ return 500;
998
+ }
999
+
1000
+ char *encoded_name = url_encode(url_name);
1001
+ if(!encoded_name) {
1002
+ free(encoded_url);
1003
+ error("%llu: Cannot URL encode string '%s'", w->id, url_name);
1004
+ return 500;
1005
+ }
1006
+
1007
+ char *encoded_guid = url_encode(machine_guid);
1008
+ if(!encoded_guid) {
1009
+ free(encoded_url);
1010
+ free(encoded_name);
1011
+ error("%llu: Cannot URL encode string '%s'", w->id, machine_guid);
1012
+ return 500;
1013
+ }
1014
+
1015
+ registry_set_cookie(w, "give-me-back-this-cookie-please");
1016
+ buffer_sprintf(w->response.header, "Location: %s/api/v1/registry?action=access&machine=%s&name=%s&url=%s&redirects=%d\r\n",
1017
+ registry_to_announce(), encoded_guid, encoded_name, encoded_url, redirects);
1018
+ free(encoded_guid);
1019
+ free(encoded_name);
1020
+ free(encoded_url);
1021
+ return 307;
1022
+ }
1023
return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, time(NULL));
1024
1025
case 'D':