Monday, July 27, 2020

SSL Handshake explained

SSL Handshake explained

If you have ever browsed an HTTPS URL through a browser, you have experienced the SSL handshake. Even though might not notice it, the browser and the website is creating an HTTPS connection using one-way SSL handshake.
The main purpose of an SSL handshake is to provide privacy and data integrity for communication between a server and a client. During the Handshake, server and client will exchange important information required to establish a secure connection.
There are two types of SSL handshakes described as one-way SSL and two-way SSL (Mutual SSL). The difference between those two is that in one -way SSL, only the client validates the identity of the server whereas in two-way SSL, both server and client validate the identity of each other. Usually, when we browse an HTTPS website, one-way SSL is being used where only our browser (client) validates the identity of the website (server). Two-way SSL is mostly used in server to server communication where both parties need to validate the identity of each other.
During an SSL handshake, the server and the client follow the below set of steps.
1. Client Hello
The client will send the information that will be required by the server to start an HTTPS connection.
In the above log, we can see that the client hello with TLS v1.2. By this, the client notifies the server that it has the support for TLS[1] versions 1.2 and below. List of ciphers[2] that are supported by the client can also be seen from the above log. Out of this list, the server will select a cipher suite that it supports. If the list contains cipher suites that server does not recognize, support, or wish to use, the server will ignore those ciphers. If no supported cipher suites were found the server will send a failure alert and close the connection.
2. Server Hello
The server will respond back with the configuration it selected from the Client Hello along with its information to proceed with the handshake. Server Hello will be as follows.
Sever will select the TLS version according to the lower of that suggested by the client in the Client Hello message and the highest supported by the server. The server will also send back the cipher suite it selected from the list of ciphers presented by the client.
Along with the Server Hello, the server will also send the certificate[3] of the server with the certificate chain. The certificate chain will be validated against the certificates in the client trust store[4].
3. Server Key Exchange Message
This message will be sent by the server to the client carrying the required details for the client to generate the pre-master secret. This message will not be sent if RSA key exchange algorithm (more in this later) or any other key exchange algorithms are used that do not require the information from the server to generate a pre-master secret.
For Elliptic Curve Diffie Hellman(ECDH)[5] key exchange, the following details on the server ECDH public key are being sent to the client.
4. Certificate Request
This is the place where one-way SSL defers from two-way SSL. In one-way SSL, the authenticity of the client is not being validated. Hence, this step is omitted in one-way SSL handshake.
During this step, the server will send a certificate request from the client with the certificate type, certificate signature algorithms and certificate authorities [6] supported by the server. There can be situations where the certificate authorities list can be empty. In such scenarios, the client may choose whether to send or avoid sending of the client certificate (depends on the client implementation)
Finally, the server sends the Server Hello Done message indicating the end of Server Hello. After sending this message, the server will wait for a client response.
5. Client Certificate
The client presents its certificate chain to the server. The certificate needs to be appropriate for the negotiated cipher suite’s key exchange algorithm, and any negotiated extensions.
6. Client Key Exchange Message
This message needs to be sent by the client following the Client Certificate message. If the client certificate is not being presented (in one-way SSL), the client key exchange message should be sent after the client receives the ServerHelloDone message.
As we all know the data transferred between the server and the client in an HTTPS connection will be encrypted. Symmetric encryption[7] is being used for this purpose as the computational cost is much lower than Asymmetric encryption. In order to use symmetric encryption, there needs to be a common key between the two ends. The purpose of this message is to generate that common key between that client and the server without exposing to an outsider.
There are two client key exchange methods described in the TLS v1.2 spec. They are RSA[8] and Diffie-Hellman.
If RSA is used as the key exchange algorithm, the client generates a 48-byte pre-master secret. The client encrypts the pre-master secret by the public key of the certificate and sends to the server. Only the server will have the corresponding private key to decrypt and get the client generated pre-master secret.
If Diffie-Hellman is used, the Diffie-Hellman parameters are transmitted to allow both client and server to generate the same pre-master secret.
After that, both sides will generate a master secret using the pre-master secret and the master secret will be used to generate the symmetric key for encrypting the session data
7. Finished
After successful authentication and generating the pre-master secrets/master secrets, a change cipher spec message will be sent by both client and server indicating that the rest of the communication will be encrypted.
The Finished message will immediately follow the change cipher spec message. This will be the first message encrypted with the negotiated algorithms. Application data will be transferred only after both parties send the finished message and verifying the content of the message.

References

Friday, July 24, 2020

https://www.journaldev.com/7128/log4j2-example-tutorial-configuration-levels-appenders

https://www.journaldev.com/7128/log4j2-example-tutorial-configuration-levels-appenders

How Log4J2 Works: 10 Ways to Get the Most Out Of It

Log4j2 is the updated version of the popular and influential log4j library, used extensively throughout the Java ecosystem for so many years. Version 2.x keeps all the logging features of its predecessor and builds on that foundation with some significant improvements, especially in the area of performance.
And of course, given how instrumental logging is for any application, both for audit and debugging purposes, choosing a solid logging library is quite an important decision.
In the following sections, we’re going to take a look at why the log4j2 library is a great choice for that decision and how we can use it in an application.

Basic Log4j2 Configuration

To start using log4j2 in your project, you simply need to add the log4j-core dependency. If you’re using Maven, you can add the following dependency to your pom.xml file:
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version>
</dependency>
And if you’re working with Gradle, you need to add the dependency to the build.gradle file:
dependencies {
  compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2'
}
Out of the box, log4j2 will automatically provide a simple configuration, if you don’t explicitly define one yourself. The default configuration logs to the console at a level of ERROR level or above.
To start logging messages using this basic configuration, all you need to do is obtain a Logger instance using the LogManager class:
private static Logger logger = LogManager.getLogger(MyService.class);
Then you can use the logger object with methods corresponding to the log level you want:
logger.error("This is an error message");

Customizing the Log4j2 Configuration

A custom log4j2 configuration can be created either programmatically or through a configuration file.
The library supports config files written in XML, JSON, YAML, as well as the .properties format. Here, we’re going to use XML to discuss all examples primarily.
First, you can override the default configuration by simply creating a log4j2.xml file on the classpath:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>
Let’s have a closer look at the tags used in this simple configuration:
  • Configurationthe root element of a log4j2 configuration file; the status attribute represents the level at which internal log4j events should be logged
  • Appendersthis element contains a list of appenders; in our example, an appender corresponding to the System console is defined
  • Loggers: this element contains a list of Logger instances. The Root element is a standard logger that outputs all messages
It’s important to understand that the Root logger is mandatory in every configuration. As discussed, if you don’t provide one, it will automatically be configured by default with a Console appender and the ERROR log level.

Configuring Appenders

In the log4j2 architecture, an appender is basically responsible for sending log messages to a certain output destination.
Here are some of the most useful types of appenders that the library provides:
  • ConsoleAppender – logs messages to the System console
  • FileAppender – writes log messages to a file
  • RollingFileAppender – writes the messages to a rolling log file
  • JDBCAppender – uses a relational database for logs
  • AsyncAppender – contains a list of other appenders and determines the logs for these to be written in a separate thread
To better understand how appenders work, let’s look at some configuration examples.

The RollingFileAppender

Logging everything into a single file is, of course, not ideal. It’s usually much better to roll over the active log file regularly – which is exactly what the RollingFileAppender does.
You’ll also be able to go beyond the basics with this type of appender and configure both a custom triggering policy as well as rollover strategy.
The triggering policy determines when the log file is rolled, meaning a new file is created, while the rollover strategy determines how the file is rolled.
As a quick example, let’s configure an appender that creates a new log file based on 3 policies:
  • OnStartupTriggeringPolicy – a new log file is created every time the JVM starts
  • TimeBasedTriggeringPolicy – the log file is rolled based on a date/time pattern
  • SizeBasedTriggeringPolicy – the file is rolled when it reaches a certain size
The configuration will use the DefaultRolloverStrategy:
<Appenders>
    <RollingFile name="RollingFileAppender" fileName="logs/app.log"
      filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
        <PatternLayout>
            <Pattern>%d [%t] %p %c - %m%n</Pattern>
        </PatternLayout>
        <Policies>
            <OnStartupTriggeringPolicy />
            <TimeBasedTriggeringPolicy />
            <SizeBasedTriggeringPolicy size="50 MB" />
        </Policies>
        <DefaultRolloverStrategy max="20" />
    </RollingFile>
</Appenders>
You can see just how flexible this style of configuration is, and how you can tune the exact semantics of your logging strategy – down to the last detail.

New call-to-action

The JDBCAppender

As the name suggests, this appender uses JDBC to write logs to a relational database.
For this configuration, you need to define a ConnectionSource, which can be either a JNDI Data Source or a custom ConnectionFactory. The logger uses the ConnectionSource to get JDBC connections, which is why it’s important to use a connection pool for better performance.
To configure the appender in the XML config file, you can use the JDBC tag:
<Appenders>
    <JDBC name="JDBCAppender" tableName="logs">
        <DataSource jndiName="java:/comp/env/jdbc/LoggingDataSource" />
        <Column name="date" isEventTimestamp="true" />
        <Column name="logger" pattern="%logger" />
        <Column name="level" pattern="%level" />
        <Column name="message" pattern="%message" />
        <Column name="exception" pattern="%ex{full}" />
    </JDBC>
</Appenders>
As you can see, the JNDI data source is simply specified using the jndiName attribute of DataSource tag. Along with the ConnectionSource, you can define the table and the columns to be used for storing the log data.

The FailoverAppender

Finally, let’s have a look at the FailoverAppender; this defines a primary appender and a list of backups that will step in to handle the logging in case the primary one fails.
For example, you can configure a primary JDBCAppender, with a secondary the RollingFile and Console appenders in case a database connection cannot be established:
<Failover name="FailoverAppender" primary="JDBCAppender">
    <Failovers>
        <AppenderRef ref="RollingFileAppender" />
        <AppenderRef ref="Console" />
    </Failovers>
</Failover>
In a production environment, having a failover strategy for your logging mechanism is always a good idea.

Configuring Layouts

While the appenders are responsible for sending log messages to a destination, the layouts are used by appenders to define how a log message will be formatted.
Here’s a brief description of some of the more commonly used layouts that log4j2 offers:
  • PatternLayout – configures messages according to a String pattern
  • JsonLayout – defines a JSON format for log messages
  • CsvLayout – can be used to create messages in a CSV format

The PatternLayout

The first type of layout we’re going to look at is the PatternLayout. This is quite a flexible solution that gives you a lot of control over the final output of the log message.
The mechanism is primarily driven by a conversion pattern which contains conversion specifiers. Each specifier begins with the % sign, followed by modifiers that control things like width and color of the message, and a conversion character that represents the content, such as date or thread name.
Let’s look at an example of configuring a PatternLayout that configures log lines to show the date, thread, log level and log message with different colors for different log levels:
<Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] 
      %highlight{%level}{FATAL=bg_red, ERROR=red, WARN=yellow, INFO=green, DEBUG=blue} - %msg%n" />
</Console>
These specifiers are well worth understanding in detail, so let’s have a closer look:
  • %d{HH:mm:ss.SSS} – outputs the date of the log event in the specified format
  • %t – outputs the thread name
  • %level – displays the log level of the message
  • %highlight{%level} – is used to define the colors for the pattern between curly brackets
  • %msg%n – outputs the log message
The output will display the log levels with different colors:
You can read more about the full set of options for defining patterns in the log4j2 documentation on PatternLayout.

The JsonLayout

Logging data using the JSON format has some significant advantages, such as making the logs easier to be analyzed and processed by logging tools down the line.
To configure the JSONLayout in log4j2, you can simply define the corresponding tag:
<JSONLayout complete="true" compact="false"/>
Setting complete=true will produce a well-formed JSON document:
[
    {
        "timeMillis" : 1496306649055,
        "thread" : "main",
        "level" : "INFO",
        "loggerName" : "RollingFileLogger",
        "message" : "Json Message",
        "endOfBatch" : false,
        "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
        "threadId" : 1,
        "threadPriority" : 5
    },
    
    ...
]
To be able to produce JSON, you also need to add the jackson-databind library to the classpath:
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.8.1</version>
</dependency>

Configuring Filters

Filters in log4j2 are used to determine if a log message should be processed or skipped.
A filter can be configured for the entire configuration or at logger or appender level.
The library provides several types of filters that can be used:
  • BurstFilter – controls the number of log events allowed
  • DynamicThresholdFilter – filters log lines based on certain attributes
  • RegexFilter – filters messages based on whether they match a regular expression
You can, for example, control the rate with which the application is allowed to log data.
In order to do, you can set up a BurstFilter and apply that to INFO messages:
<Filters>
    <BurstFilter level="INFO" rate="10" maxBurst="100"/>
</Filters>
This will selectively ignore control the traffic of INFO level messages and below while making sure you’re not losing any of the more important messages above INFO.
In this case, rate defines the average logs messages that should be processed per second, and maxBurst controls the overall size of the traffic burst before the filter starts eliminating log entries.
Similarly, we can configure the appender only to accept log messages that match a specific regular expression:
<Appenders>
    <JDBC name="JDBCAppender">
      <RegexFilter regex="*jdbc*" onMatch="ACCEPT" onMismatch="DENY"/>
    </JDBC>
</Appenders>
Overall, this filtering mechanism can be used with great precision to make sure each appender in your overall logging configuration is tracking the right information. The ability to only log very specific and relevant information generally leads to very quick root cause analysis, especially in complex systems – especially when coupled with a powerful log viewing tool.

Configuring Loggers

Besides the Root logger, we can also define additional Logger elements with different log levels, appenders or filters. Each Logger requires a name that can be used later to reference it:
<Loggers>
    <Logger name="RollingFileLogger">
        <AppenderRef ref="RollingFileAppender" />
    </Logger>
</Loggers>
To write log messages using this particular Logger, you can obtain a reference to it using the LogManager class:
Logger rfLogger = LogManager.getLogger("RollingFileLogger");
rfLogger.info("User info updated");
Another very common way to structure the hierarchy of these loggers is based on the Java class:
Logger logger = LogManager.getLogger(MyServiceTest.class);

Using Lookups

Lookups represent a way to insert external values into the log4j2 configuration. We’ve already seen an example of the date lookup in the RollingFileAppender configuration:
<RollingFile name="RollingFileAppender" fileName="logs/app.log"
  filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
The ${date:yyy-MM} lookup will insert the current date into the file name, while the preceding $ is an escape character, to insert the lookup expression into the filePattern attribute.
You can also insert System properties values into log4j2 configuration using the format ${sys:property_name}:
<File name="ApplicationLog" fileName="${sys:path}/app.log"/>
Another type of information you can lookup and insert is Java environment information:
<PatternLayout header="${java:version} - ${java:os}">
    <Pattern>%d %m%n</Pattern>
</PatternLayout>
You can find more details on the kind of data you can insert through lookups in the log4j2 documentation.

Programmatic Configuration

Besides configuration files, log4j2 can also be configured programmatically. There are a few different ways to do that:
  • create a custom ConfigurationFactory
  • use the Configurator class
  • modify the configuration after initialization
  • combine properties files and programmatic configuration
Let’s take a look at how to configure a layout and appender programmatically:
Loggerj ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();

PatternLayout layout = PatternLayout.newBuilder()
  .withConfiguration(config)
  .withPattern("%d{HH:mm:ss.SSS} %level %msg%n")
  .build();

Appender appender = FileAppender.newBuilder()
  .setConfiguration(config)
  .withName("programmaticFileAppender")
  .withLayout(layout)
  .withFileName("java.log")
  .build();
    
appender.start();
config.addAppender(appender);
Next, you can define a logger using the LoggerConfig class, associate the appender to it, and update the configuration:
AppenderRef ref = AppenderRef.createAppenderRef("programmaticFileAppender", null, null);
AppenderRef[] refs = new AppenderRef[] { ref };

LoggerConfig loggerConfig = LoggerConfig
  .createLogger(false, Level.INFO, "programmaticLogger", "true", refs, null, config, null);
loggerConfig.addAppender(appender, null, null);
config.addLogger("programmaticLogger", loggerConfig);
ctx.updateLoggers();
Then, you can start using the logger as usual:
Logger pLogger = LogManager.getLogger("programmaticLogger");
pLogger.info("Programmatic Logger Message");
This style of fluent API can lead to a quicker development and iteration on more complex logging configurations because you’re now benefiting from the benefits of working directly with Java code.
However, given that XML can still be more readable and compact, you can often develop the configuration programmatically and then convert it to XML when everything’s done.

Custom Log Levels

The built-in log levels for log4j2 are:
  • OFF
  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE
  • ALL
In addition to these, you can also define a custom log level according to your application needs.
For example, to define this new log level, you can make use of the Level.forName() API – specifying the new level name and an integer that represents the place of the level in the log levels hierarchy:
Level myLevel = Level.forName("NEW_LEVEL", 350);
To determine what integer value to use, you can have a look at the values defined for the other log levels in the log4j2 documentation:
The 350 value puts the level between WARN and INFO, which means the messages will be displayed when the level is set to INFO or above.
To log a message at the custom level, you need to use the log() method:
logger.log(myLevel, "Custom Level Message");
The equivalent XML configuration could be:
<CustomLevels>
    <CustomLevel name="NEW_XML_LEVEL" intLevel="350" />
</CustomLevels>
Then it can be used via the standard log API:
logger.log(Level.getLevel("NEW_XML_LEVEL"),"Custom XML Level Message");
The new custom levels will be displayed in the same way as the standard ones:
11:28:23.558 [main] NEW_LEVEL - Custom Level Message
11:28:23.559 [main] NEW_XML_LEVEL - Custom XML Level Message

Migrating from Log4j 1.x

If you’re migrating an application using the 1.x version of the library to the current 2.x version, there are a couple of routes you can follow:
  • use the log4j 1.x bridge
  • manually update the API and the configuration
Using the bridge is trivial. You only need to replace the log4j dependency with log4j-1.2-api library:
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-1.2-api</artifactId>
    <version>2.8.2</version>
</dependency>
While this is the faster method, it has the disadvantage of being limited in the type of configuration that can be converted.
The manual method is, of course, more work, but will eventually lead to a more flexible and powerful logging solution.
Here are some of the most common type of changes you’ll have to do:
  • change the package from org.apache.log4j to org.apache.logging.log4j
  • change instances of Logger.getLogger() and Logger.getRootLogger() to LogManager.getLogger() and LogManager.getRootLogger()
  • change Logger.getEffectiveLevel() to Logger.getLevel()
  • replace Logger.setLevel() calls with Configurator.setLevel()
  • replace <log4j2:configuration> tag with <Configuration>
  • replace <appender> tag with a tag corresponding to the type of the appender, such as <Console>
  • replace <layout> tag with a tag corresponding to the type of the layout, such as <PatternLayout>
  • replace <appender-ref> tag with <AppenderRef>

Conclusion

Log files are critical in any production environment, and choosing a good logging solution can be the difference between spending 5 minutes and spending a full day to understand a problem in production.
Log4j2 is a powerful and robust logging solution for modern Java applications, with a wide range of configuration options.
It allows for easy configuration of advanced logging best practices such as rolling files, different types of logging output destinations, support for structured logging formats such as JSON or XML, using multiple loggers and filters, and custom log levels.
Finally, when you need to go beyond manually analyzing log data, definitely check out the logging capabilities included in Retrace APM.