Prevent GDScript language server from listening to external hosts by default

* Add bind_ip property to WebSocketServer defaulting to "*" (listen to everyone)
* Set default for GDscript Language Server to listen only to localhost

Fixes potential security issue with GDScript language server being exposed to the
broad net by default.
Since it is the server which primary usage is to provide utility to the local
editor there is no need to expose it.
This commit is contained in:
Houkime 2020-01-02 14:02:29 +00:00
parent 40f0649e5b
commit e1a0ce5af9
7 changed files with 28 additions and 4 deletions

View file

@ -156,7 +156,7 @@ void GDScriptLanguageProtocol::poll() {
server->poll();
}
Error GDScriptLanguageProtocol::start(int p_port) {
Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) {
if (server == NULL) {
server = dynamic_cast<WebSocketServer *>(ClassDB::instance("WebSocketServer"));
ERR_FAIL_COND_V(!server, FAILED);
@ -165,6 +165,7 @@ Error GDScriptLanguageProtocol::start(int p_port) {
server->connect("client_connected", this, "on_client_connected");
server->connect("client_disconnected", this, "on_client_disconnected");
}
server->set_bind_ip(p_bind_ip);
return server->listen(p_port);
}

View file

@ -77,7 +77,7 @@ public:
_FORCE_INLINE_ bool is_initialized() const { return _initialized; }
void poll();
Error start(int p_port);
Error start(int p_port, const IP_Address &p_bind_ip);
void stop();
void notify_all_clients(const String &p_method, const Variant &p_params = Variant());

View file

@ -84,7 +84,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
void GDScriptLanguageServer::start() {
port = (int)_EDITOR_GET("network/language_server/remote_port");
use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
if (protocol.start(port) == OK) {
if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
ERR_FAIL_COND(thread != NULL);

View file

@ -83,6 +83,9 @@
</method>
</methods>
<members>
<member name="bind_ip" type="String" setter="set_bind_ip" getter="get_bind_ip">
When not set to [code]*[/code] will restrict incoming connections to the specified IP address. Setting [code]bind_ip[/code] to [code]127.0.0.1[/code] will cause the server to listen only to the local host.
</member>
<member name="ca_chain" type="X509Certificate" setter="set_ca_chain" getter="get_ca_chain">
When using SSL (see [member private_key] and [member ssl_certificate]), you can set this to a valid [X509Certificate] to be provided as additional CA chain information during the SSL handshake.
</member>

View file

@ -34,6 +34,7 @@ GDCINULL(WebSocketServer);
WebSocketServer::WebSocketServer() {
_peer_id = 1;
bind_ip = IP_Address("*");
}
WebSocketServer::~WebSocketServer() {
@ -49,6 +50,10 @@ void WebSocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &WebSocketServer::get_peer_port);
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_bind_ip"), &WebSocketServer::get_bind_ip);
ClassDB::bind_method(D_METHOD("set_bind_ip"), &WebSocketServer::set_bind_ip);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bind_ip"), "set_bind_ip", "get_bind_ip");
ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key);
ClassDB::bind_method(D_METHOD("set_private_key"), &WebSocketServer::set_private_key);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", 0), "set_private_key", "get_private_key");
@ -67,6 +72,16 @@ void WebSocketServer::_bind_methods() {
ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id")));
}
IP_Address WebSocketServer::get_bind_ip() const {
return bind_ip;
}
void WebSocketServer::set_bind_ip(const IP_Address &p_bind_ip) {
ERR_FAIL_COND(is_listening());
ERR_FAIL_COND(!p_bind_ip.is_valid() && !p_bind_ip.is_wildcard());
bind_ip = p_bind_ip;
}
Ref<CryptoKey> WebSocketServer::get_private_key() const {
return private_key;
}

View file

@ -41,6 +41,8 @@ class WebSocketServer : public WebSocketMultiplayerPeer {
GDCLASS(WebSocketServer, WebSocketMultiplayerPeer);
GDCICLASS(WebSocketServer);
IP_Address bind_ip;
protected:
static void _bind_methods();
@ -67,6 +69,9 @@ public:
void _on_disconnect(int32_t p_peer_id, bool p_was_clean);
void _on_close_request(int32_t p_peer_id, int p_code, String p_reason);
IP_Address get_bind_ip() const;
void set_bind_ip(const IP_Address &p_bind_ip);
Ref<CryptoKey> get_private_key() const;
void set_private_key(Ref<CryptoKey> p_key);

View file

@ -165,7 +165,7 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp
for (int i = 0; i < p_protocols.size(); i++) {
pw[i] = p_protocols[i].strip_edges();
}
_server->listen(p_port);
_server->listen(p_port, bind_ip);
return OK;
}