Intercepting and parsing Logger or console output without disturbing it - java

I am having some trouble with Java. What I want is pretty simple,
I am developing a plugin for a mod of a well-known game, Minecraft, and I need to be able to parse every line of console output that comes through to STOUT.
I've looked around on the internet but I can't seem to find anything I can use to do this. I know that some console output is through the default Logger, and some is through system.out. I have a function, parseConsole(String line) that will parse the line and do something if it contains a word, etc etc. I want this function to be called for every line of output displayed on the console, but it must not interrupt the flow, as in every line will still be sent to the console after being parsed by my function.

you can use System.setOut() to replace the console PrintStream. you can replace this with an implementation which inspects the text on its way to the console.
here is an example of how you might filter:
public class MyFilterPrintStream extends PrintStream {
#Override public void print(String s) {
// ... process output string here ...
// pass along to actual console output
super.print(s);
}
}
// install my filter
System.setOut(new MyFilterPrintStream(System.out));

Related

Sanitize/validate variable to avoid cross-site-scripting attack

I get this issue with CheckMarx security scan:
Method exec at line 69 of
web\src\main\java\abc\web\actions\HomeAction.java gets user input for
the CNF_KEY_COSN element. This element’s value then flows through the
code without being properly sanitized or validated and is eventually
displayed to the user in method logException at line 905 of
web\src\main\java\gov\abc\external\info\ServiceHelper.java. This may
enable a Cross-Site-Scripting attack.
Line 69 of HomeAction.java:
String cosn = (String) request.getParameter(CNF_KEY_CON);
Line 905 in ServiceHelper.java just logs the error:
private static void logException(InfoServiceException exception, String message) {
String newMessage = message + ": " + exception.getMessageForLogging();
try {
log.error(newMessage, exception);
} catch (Exception e) {
// fallback to console
System.out.println("error logging exception ->");
e.printStackTrace(System.out);
System.out.println("exception ->");
System.out.print(newMessage);
if (exception != null) exception.printStackTrace(System.out);
}
}
Changed another block of code in HomeAction.java to:
if(cosn!= null && cosn.matches("[0-9a-zA-Z_]+")) {
...
}
But that didn't help. How do I validate/sanitize/encode Line 69. Any help is much appreciated.
Thanks
You can sanitise strings for XSS attacks using Jsoup there is a clean() method for this. You would do something like this to sanitise the input:
String sanitizedInput = Jsoup.clean(originalInput, "", Whitelist.none(), new OutputSettings().prettyPrint(false));
Checkmarx defines a set of sanitizers that you can check in the system.
Based on your source code snippets; i assume that;
i) you are appending 'cosn' to 'message'
ii) application is web-based in nature (in view of the request.getParameter)
iii) message is been displayed to the console or log to a file.
You could consider using Google Guava or Apache Commons Test to html escape the input.
import com.google.common.html.HtmlEscapers;
public void testGuavaHtmlEscapers(){
String badInput = "<script> alert me! <script>";
String escapedLocation = HtmlEscapers.htmlEscaper().escape(badInput);
System.out.println("<h1> Location: " + escapedLocation + "<h1>");
}
import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;
public void testHtmlEscapers(){
String badInput = "<script> alert me! <script>";
System.out.println(escapeHtml4(badInput));
}
I would also consider if there is sensitive information, that i should mask e.g., using String.replace.
public void testReplace(){
String email = "some-email#domail.com";
String masked = email.replaceAll("(?<=.).(?=[^#]*?.#)", "*");
System.out.println(masked);
}
Above 3 sanitization methods will work similarly.
This is likely a false positive (technically, "not exploitable" in Checkmarx) with regard to XSS, depending on how you process and display logs. If logs are ever displayed in a browser as html, it might be vulnerable to blind XSS from this applications point of view, but it would be a vulnerability in whatever component displays logs as html, and not in the code above.
Contrary to other answers, you should not encode the message here. Whatever technology you use for logging will of course have to encode it properly for its own use (like for example if it's stored as JSON, data will have to be JSON-encoded), but that has nothing to do with XSS, or with this problem at all.
This is just raw data, and you can store raw data as is. If you encode it here, you will have a hard time displaying it in any other way. For example if you apply html encoding, you can only display it in html (or you have to decode, which will negate any effect). It doesn't make sense. XSS would arise if you displayed these logs in a browser - in which case whatever displays it would have to encode it properly, but that's not the case here.
Note though that it can still be a log injection vulnerability. Make sure that whatever way you store logs, that log store **does* apply necessary encoding. If it's a text file, you probably want to remove newlines so that fake lines cannot be added to the log. If it's json, you will want to encode to json, and so on. But that's a feature of your log facility, and not the code above.

Method does nothing if called within an if, if called directly from on event it works

I`m building a discord bot with jda, made a method to use mXparser to get a math operation as an input from the chat e.g: /math 5+1
wrote everything to get the message, separate the arguments from the input on the chat, everything works until I put the code inside an IF statement that checks if it actually starts with "/math", the code inside it uses mXparser to calculate everything and send it back to chat.
Tried just about everything I could think of, taking all variables off the method, rewriting everything, I don`t get any errors either as stack trace or in the code editor, it just doesnt go through, tried just printing everything and it works fine as well, printing all the values on the console, everything seems to be right.
This part is where I check for the message, get the Strings and trim everything
public void onMessageReceived(MessageReceivedEvent event) {
this.messageReceived = event;
this.prefix = Main.prefix;
checkPrefix = messageReceived.getMessage().getContentRaw().split("\\s" + prefix);
mainArg = checkPrefix[0];
checkArgs = messageReceived.getMessage().getContentRaw().split(" ");
callAllCommands();
}
Here is the command to take the actual expression from the chat input calculate it and send it back.
private void mathCommand() {
mathexp = new Expression(checkArgs[1]);
messageReceived.getChannel().sendTyping().queue();
essageReceived.getChannel().sendMessage(Double.toString(mathexp.calculate())).queue();
}
This is inside the callAllCommands() method, that is how it is supposed to work, if the command on the chat is /math then the expression e.g: /math 1+1 it will send the result back, if I take off the IF statement it works just fine but then I can't check for the command. The other commands do work fine with the IF statement
if (mainArg.contentEquals(prefix + "math")) {
mathCommand();
}
I don't really get any errors, it just does not work, sorry if I missed something really simple, i`m not that experienced yet.

View output in Aws Lambda basic function

i'm trying to invode aws lambda function using Java in my Eclipse, if i pass input as any string, the function is calling successfully but, i'm seeing null as the output, but i'm expecing the input text itself as output.
Here is my code
package simpledynamodb;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public class LambdaFunctionHandler implements RequestHandler<String, String> {
#Override
public String handleRequest(String input, Context context) {
context.getLogger().log("Input is working");
context.getLogger().log("Input: " + input);
// TODO: implement your handler
return null;
}
}
The output looks like
Uploading function code to dynamodbmaven...
Upload success. Function ARN: arn:aws:lambda:us-west-2:169456523019:function:dynamodbmaven
Invoking function...
==================== FUNCTION OUTPUT ====================
null
In my code i'm passing "Hello world" as input text, i'm suppose to see the passed string instead i'm getting null.
My handler class, everything seems to be fine. Here is the pic of my lambda configuration
Can you tell me where i'm wrong in this?.
I'm super late here but the reason you aren't seeing the output is because you are looking at the output in Eclipse - which only returns the result of your function invocation.
You should look at the Cloudwatch Logs for the Lambda to get the logs of the run.
It's printing null because that's what the function is returning.
I assume when you say you should be getting the input text as output, what you really mean is that you should be seeing in the input string in the logs. I'm guessing you have the logging configured such that those logs aren't printing. To get past the logging configuration issues just to see what your input string is, you might try using System.out instead of context.getLogger().log

Is there a way to make command text follow input?

Say i want to print a text prompt in java, and then get input from user from System.in. But another thread can write to System.out and "takes down" the input but the text prompt stays up, which is normal.
Enter input here ->
<waiting for input ...>
But if a thread writes something the following occurs:
Enter input here ->
...
...
...
Thread output here
...
...
<Waits for input here>
Is there any trick to "bind" the input with the prompt text?
You could wrap your system.outs into a logging class, and when you want to print something add it to a queue in the new logging class.
When ever you ask for user input, have it activate a lock in the logging class so anything in the queue doesn't get printed until the user input is submitted, then have all the output in the queue get printed.
This will result in all the output text being paused while input is coming in. It won't interrupt your input, so the input will be bound around the cursor, but you also won't get any output. Up to you if that's worth it.
Is there any trick to "bind" the input with the prompt text?
Nope. It's your code; it's up to you to cooperate with yourself. That could mean building (or finding a library which provides) a wrapper API around System.(in|out) so you don't have to worry about accidentally causing this issue. But no, there is no magical silver bullet.
I am not sure if any existing implementations exist but this task should be simple enough.
Make a class e.g SyncConsole which synchronizes your prints and reads.
Basically have only SyncConsole singleton in your code that writes and reads to the io streams of the console.
Then your program can do something like
SyncConsole.readInput("Text to display");
SyncConsole.print("Text");
These calls can then be properly synchronized to suit your needs. E.g if some code requested input, buffer requests to print till the input has been received and so forth.
If you are familiar with concurrency in java this should be fairly simple to build and will give you the desired behaviour.
import java.util.LinkedList;
import java.util.Queue;
public class MainDemo {
public void queueExample() {
Queue queue = new LinkedList();
queue.add("Java");
queue.add("DotNet");
queue.offer("PHP");
queue.offer("HTML");
System.out.println("remove: " + queue.remove());
System.out.println("element: " + queue.element());
System.out.println("poll: " + queue.poll());
System.out.println("peek: " + queue.peek());
}
public static void main(String[] args) {
new MainDemo().queueExample();
}
}

Removing access to System.out in java

I maintain an application which acts as a container for multiple individual programs. These programs have their own dedicated logging facility, i.e. everything they log does to a special log file.
Nevertheless, application developers seem to love to throw System.out.println and e.printStackTrace calls all over, making it impossible to maintain a clean console when running the container.
How can I prevent these applications from polluting System.out and System.err?
Implementation notes:
the applications use Log4j for logging;
the container also uses the console for logging, but it is strictly reserved for lifecycle events and problems, so I still need the console;
the applications are loaded using a custom classloader, but no security checks are applied.
Update:
Simply redirecting System.out would not work since it redirects all output, so something like this fails:
System.setOut(new PrintStream(new OutputStream() {
#Override
public void write(int b) {
throw new Error("Not on my watch you don't");
}
}));
Logger logger = Logger.getLogger(Runner.class);
logger.info("My log message");
This should succeed.
Update 2:
The applications are loaded and configured using code similar to
App app = new UrlClassLoader(...).loadClass(className)).newInstance();
app.setLogger(loggerForClass(app));
Log4j is loaded from the system class loader.
Assuming that you can control your containers output you can do the following:
import java.io.*;
public class SysOut {
public static void main(String[] args) throws Exception {
PrintStream pw = new PrintStream(new FileOutputStream("a.txt"));
PrintStream realout = System.out;
System.setOut(pw);
System.out.println("junk");
realout.print("useful");
}
}
$ java SysOut
useful
$ cat a.txt
junk
You can use System.setOut() and System.setErr() to redirect stdout and stderr to instances of PrintStream.
While Java defines a standard System.out and System.err, these can be overwritten with your own streams. See http://www.devx.com/tips/Tip/5616
Basically you can set up new streams that either pipe to the logging, or simply let data flop off into nothingness. My preference would be the latter, as it would instantly cure developers from relying on System.out and err as anything they write there just disappears.
**Update:
I just reread your stipulations in the question and see you still need the console for the container application. This might still work if you write a wrapper around the standard stream so you can check each call and see if it is coming from the parent application (and pass it on) or a child application (and block it)
Use aversion therapy. A visit from "The Inspectors" is scheduled whenever any code is checked in containing unpleasant constructs.
Nice cubicle you got ere, be shame if anyfing appened to it.
If you have a headless build mechanism, ant or such like then you could add CheckStyle to the build and configure checkstyle to fail the build if it finds any System.out.println or e.printStackTrace in the code.
If you don't have a headless build I would recommend that you build one as it means you have repeatable, predictable builds.
System.setOut will redirect all output - but the PrintStream you supply can decide how the output is handled. Thus I'm sure you could provide such a stream that would only actually print statements from your application.
The only tricky part really is being able to detect what's a valid call and what's not. A working, but likely very slow way to do this, would be to call Thread.currentThread().getStackTrace() and see what code (or package, at least) is calling you (simply returning if it's not a valid one). I wouldn't recommend this though as the performance hit would be staggering, especially doing this on every byte read.
A better idea might be to set a ThreadLocal flag in all of your valid, container threads. Then you can implement the PrintStream something like the following:
public class ThreadValidity extends ThreadLocal<Boolean>
{
private static final INSTANCE = new ThreadValidity();
#Override Boolean initialValue() { return false; }
public static ThreadValidity getInstance() { return INSTANCE; }
}
class VerifyingPrintStream extends PrintStream
{
private boolean isValidThread()
{
return ThreadValidity.instance().get();
}
public void println(String s)
{
if (!isValidThread()) return;
super.println(s);
}
public void println(Object o)
{
if (!isValidThread()) return;
super.println(o);
}
// etc
}
Alternatively, if you're able to change the printlns in the container code, things get easier. You can hand off all the console writes to a specific worker; and have this worker "steal" System.out (store it in its own field and use it directly for writing output) while setting the actual System.out to a no-op writer.
The key here is to configure log4j before redirecting the output streams, e.g.
BasicConfigurator.configure();
System.setOut(...);
System.setErr(...);
System.out.println("I fail");
Logger.getLogger(...).info("I work");
Convert the System.out and System.err streams to special implementations that throw a RuntimeException("Use logging instead of System.out") every time a character is written.
If your container is important, they will get the idea pretty quickly :)
(For extra bonus throw OutOfMemoryException instead ;-))
What I have done is redirect the PrintStream for System.out and System.err to commons-logging as INFO and ERROR level logging respectively.
This gets trickier if you want some threads to be able to write to the console or you want logs to go to the console as well but it can be done.
You can actually get and store System.out/err before replacing them.
OutputStream out=System.getOut(); // I think the names are right
System.setOut(some predefined output stream, null won't work);
out.println("Hey, this still goes to the output");
System.out.println("Oh noes, this does not");
I've used this to intercept all the System.out.println's in the codebase and prefix each line of output with the method name/line number it came from.
Close the System.out and System.err streams.
We use the log4j trick but log to separate files (stdout.log, stderr.log). It's not useful to have their output mixed in with the parts that actually understand logging...

Categories

Resources