forked from Qortal/qortal
Added "apiKeyDisabled" setting to bypass API key / loopback checking for those who need it.
This should only be used if all of the following conditions are true: a) Your node is private and not shared with others b) Port 12391 (API port) isn't forwarded c) You have granted access to specific IP addresses using the "apiWhitelist" setting The node will warn on startup if this setting is used without a sensible access control whitelist.
This commit is contained in:
parent
705e7d1cf1
commit
8a7446fb40
@ -14,6 +14,8 @@ import java.security.SecureRandom;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.rewrite.handler.RedirectPatternRule;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
@ -50,6 +52,8 @@ import org.qortal.settings.Settings;
|
||||
|
||||
public class ApiService {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(ApiService.class);
|
||||
|
||||
private static ApiService instance;
|
||||
|
||||
private final ResourceConfig config;
|
||||
@ -203,6 +207,9 @@ public class ApiService {
|
||||
context.addServlet(TradeBotWebSocket.class, "/websockets/crosschain/tradebot");
|
||||
context.addServlet(PresenceWebSocket.class, "/websockets/presence");
|
||||
|
||||
// Warn about API security if needed
|
||||
this.checkApiSecurity();
|
||||
|
||||
// Start server
|
||||
this.server.start();
|
||||
} catch (Exception e) {
|
||||
@ -222,4 +229,23 @@ public class ApiService {
|
||||
this.server = null;
|
||||
}
|
||||
|
||||
private void checkApiSecurity() {
|
||||
// Warn about API security if needed
|
||||
boolean allConnectionsAllowed = false;
|
||||
if (Settings.getInstance().isApiKeyDisabled()) {
|
||||
for (String pattern : Settings.getInstance().getApiWhitelist()) {
|
||||
if (pattern.startsWith("0.0.0.0/") || pattern.startsWith("::/") || pattern.endsWith("/0")) {
|
||||
allConnectionsAllowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (allConnectionsAllowed) {
|
||||
LOGGER.warn("Warning: API key validation is currently disabled, and the API whitelist " +
|
||||
"is allowing all connections. This can be a security risk.");
|
||||
LOGGER.warn("To fix, set the apiKeyDisabled setting to false, or allow only specific local " +
|
||||
"IP addresses using the apiWhitelist setting.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ public abstract class Security {
|
||||
public static final String API_KEY_HEADER = "X-API-KEY";
|
||||
|
||||
public static void checkApiCallAllowed(HttpServletRequest request) {
|
||||
// If API key checking has been disabled, we will allow the request in all cases
|
||||
boolean isApiKeyDisabled = Settings.getInstance().isApiKeyDisabled();
|
||||
if (isApiKeyDisabled)
|
||||
return;
|
||||
|
||||
String expectedApiKey = Settings.getInstance().getApiKey();
|
||||
String passedApiKey = request.getHeader(API_KEY_HEADER);
|
||||
|
||||
|
@ -68,6 +68,9 @@ public class Settings {
|
||||
};
|
||||
private Boolean apiRestricted;
|
||||
private String apiKey = null;
|
||||
/** Whether to disable API key or loopback address checking
|
||||
* IMPORTANT: do not disable for shared nodes or low-security local networks */
|
||||
private boolean apiKeyDisabled = false;
|
||||
private boolean apiLoggingEnabled = false;
|
||||
private boolean apiDocumentationEnabled = false;
|
||||
// Both of these need to be set for API to use SSL
|
||||
@ -356,6 +359,10 @@ public class Settings {
|
||||
return this.apiKey;
|
||||
}
|
||||
|
||||
public boolean isApiKeyDisabled() {
|
||||
return this.apiKeyDisabled;
|
||||
}
|
||||
|
||||
public boolean isApiLoggingEnabled() {
|
||||
return this.apiLoggingEnabled;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user