Home

07 Mar 2013

Auditing and Logging

Auditing and logging are great importance to network administrators to address the issue of accountability. These tools, when implemented at the application level can be very powerful investigation tools. They can help confirm that developers are enforcing security policies and that users are accountable for their actions. Logging refers to implementation-level events for debugging. Auditing refers to domain-level transactions that reflect accountability, such as a user logging in.

Log Successful Access Attempts

It’s a good idea to log both successful and failed connection attempts. It’s common to log failed connection attempts because it’s an obvious sign someone is trying out passwords. But what if someone has stolen a password? It’s a good idea to log the successful attempts to make sure an intrusion doesn’t happen without anyone noticing.

Never Log Sensitive Data

Make sure you do not log user sensitive data. Even if the log file seems mundane, a developer may add more log commands in the future. Encrypt and store the log in a secure place.

Customizing NSLog

Here is an example of overriding the default functionality of NSLog to provide more functionality. It expands to get the line number and function that called the log. You can also comment out all NSLogs in one place for your release-mode:

#define NSLog(args...) _CFLog(@"DEBUG ", __FILE__,__LINE__,__PRETTY_FUNCTION__,args);

void _CFLog(NSString *prefix, const char *file, int lineNumber, const char *funcName, NSString *format,...)
{
    //local variables, setup current date and time, arguments and message
    va_list ap;
    va_start(ap, format);
    const char *formatString = "%s %s%50s:%3d - %s";
    format = [format stringByAppendingString:@"\n"];
    NSString *dateString = [[self dateFormatter] stringFromDate:[NSDate date]];
    NSString *msg = [[NSString alloc] initWithFormat:[NSString stringWithFormat:@"%@",format] arguments:ap];
    va_end (ap);
    
    //write to console file if enabled
#ifdef ENABLE_LOGGING_TO_CONSOLE
    fprintf(stderr, formatString, [dateString UTF8String], [prefix UTF8String], funcName, lineNumber, [msg UTF8String]);
#endif
    
    //save log in cache
    if (. . .validate the string)
    {
        char *charBuffer = NULL;
        size_t size;
        size = snprintf(NULL, 0, formatString, [dateString UTF8String], [prefix UTF8String], funcName, lineNumber, [msg UTF8String]);
        charBuffer = (char *)malloc(size + 1);
        if (charBuffer)
        {
            snprintf(charBuffer, size + 1, formatString, [dateString UTF8String], [prefix UTF8String], funcName, lineNumber, [msg UTF8String]);
            // -> Add code to save or send log here
        }
        free(charBuffer);
    }
}

Sanitizing Logs

Often logs are stored to an SQLite database or sent to another platform for processing. If you’re logging user-input or you’ll parse logs in any way, make sure to sanitize the input for command-injection attacks. If a server is down, make sure you rate limit the frequency and number of logs sent, network retries and error messages so that a denial of service attack is less likely.

For more information about collection of logs and privacy, see the Protecting the User’s Data on iOS and Data Privacy for Android tutorials.