4

Here's a minimal test case:

#include <stdio.h>
#include <stdlib.h>

int main ( int argc , char **argv )
{
        const char abc [15] = "abcdefg\0";
        printf ("%s\n" , abc);
        return 0;
}

And you do strings test , you should see abcdefg , as it's stored in read only area.

So , what's the best way to prevent user from reading this string , with "strings" command , e.g I don't want users to know my SQL phrase

Antoine
  • 5,158
  • 1
  • 24
  • 37
daisy
  • 22,498
  • 29
  • 129
  • 265
  • How about declaring the varible as private? such that other process cannot see this variable? – Muthu Ganapathy Nathan Mar 11 '12 at 08:38
  • 3
    @EAGER_STUDENT it will not work: as long as the program runs in user space, users will be able to read the string as it's appears in the binary in clear text, private or not. The only solution I can think of involves a daemon running as another user responding to your program's requests. – Antoine Mar 11 '12 at 08:41
  • http://stackoverflow.com/questions/3036134/encrypting-password-in-compiled-c-or-c-code – user1227804 Mar 11 '12 at 08:47
  • 2
    Wait, you're doing this so you can have a program that connects to a remote SQL server? If that's the case, then make an API for interacting with the server, don't have the program connect directly. (Unless of course the program is only ever meant for your use.) – Corbin Mar 11 '12 at 08:49
  • 7
    If you are sending the SQL plaintext then you can't stop it being read. Don't waste your time. – David Heffernan Mar 11 '12 at 08:49
  • @Corbin I had to store SQL phrase like "insert into XX (X,X) values (?,?)" , or I'm confused – daisy Mar 11 '12 at 09:04
  • 1
    Is this binary connecting directory to your SQL server? What exactly is the use of this binary? You might have much bigger security concerns than someone seeing your insert queries. – Corbin Mar 11 '12 at 09:07

3 Answers3

11

One solution would be to write an additional program that runs as another user, and read credentials from a location where it is not accessible by users you want to protect credentials from. This program would expose an API (through TCP/IP or any message passing interface or remote procedure call) that do not need to connect to the database directly, but responds only to requests you're interested in.

Another approach is to set the setuid bit on your program, and read credentials from a location where users have no read access. Give the program an owner that is allowed to read the file containing the query, using chown. When executed, your program will obtain privileges to read the file.

Like said in Nawaz answer (and Binyamin Sharet), you could use obfuscation techniques to make it harder to read the query (in particular, it would not work with strings anymore), but keep in mind that someone with more knowledge will be able to find the string using a deassembler or a debugger, or simply by running your program in strace. It makes this approach unsuitable to store sensitive information, like connection credentials: as long as a binary can connect, it contains credential, anyone with some knowledge in computer security know that and may reverse engineer your program to retrieve your password.

As a general guideline, if you need to protect information from a user executing your program, never give this information to the program. It is the only way to make sure it can't be read.

RedX
  • 14,749
  • 1
  • 53
  • 76
Antoine
  • 5,158
  • 1
  • 24
  • 37
5

You can store the strings XORed with some constant buffer, and during usage recover the original string. Not that easy to maintain though...

For example, the string "hello", XORed with 0x55 is:

hello:  0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00
0x55:   0x55, 0x55, 0x55, 0x55, 0x55, 0x55
result: 0x3D, 0x30, 0x39, 0x39, 0x3A, 0x55

So we store the buffer:

char enc_str[] = { 0x3D, 0x30, 0x39, 0x39, 0x3A, 0x55 };

This is our decryption function (simplified):

#define DEC_STR(X, Y) getDecryptedStr(X, Y sizeof(Y))
void getDecryptedStr(char * dec_str, char * enc_str, size_t size) {
    int i;
    for (i = 0; i < size; ++i) {
        dec_str[i] = enc_str[i] ^ 0x55;
    }
}

And that's how we use it:

char clear_str[sizeof(enc_str)];
DEC_STR(clear_str, enc_str);
MByD
  • 135,866
  • 28
  • 264
  • 277
1

Depending on your requirement and feasibility, you could do these:

  • One approach may involve storing all strings in a file in binary format so no can can read it, and when you need a string, you can read it from the file. You can use key-value when storing strings in the file, and while retrieving it, you could use the key to read the associated string.

  • Other approach may involve some form of encryption. Store the encrypted strings in the program itself, and when you need it, decrypt it before using it.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    You cannot say it is "unnecessarily" hard unless you have a better approach. – Nawaz Mar 11 '12 at 08:43
  • 2
    @Nawaz - maybe I miss something - why would it be more difficult to recognize them using `strings`? – MByD Mar 11 '12 at 08:48
  • @BinyaminSharet: Which approach are you talking about? – Nawaz Mar 11 '12 at 08:49
  • @BinyaminSharet: You think, `strings` would join the individual characters to get the phrase "abcdefg"? – Nawaz Mar 11 '12 at 08:52
  • 4
    It is unnecessary because you can always see the string. At some point the string needs to be assembled in memory for the query to be executed. You won't see it with strings, but with a disassembler and a bit of patience you will find the string. – nico Mar 11 '12 at 08:54
  • @DavidHeffernan: Ohh.. I didn't know that if the compiler would really do that. – Nawaz Mar 11 '12 at 08:54
  • @nico: In that case, it is not *unnecessary*, you could have said it is simply wrong, *because you can always see the string* – Nawaz Mar 11 '12 at 08:55
  • 1
    @Nawaz the assembly generated for your 2 string definitions will likely be exactly identical to the assembly generated for the definition given in the question. – Corbin Mar 11 '12 at 08:57