2011-10-11 41 views
6

Tôi có một hàm trả về một chuỗi:C: Quay trở lại chuỗi từ chức năng

const *char getMyPassword() 
{ 
    return "mysecretpassword"; 
} 

Vâng, nó đã làm việc một cách hoàn hảo, nhưng tôi phát hiện ra rằng nếu tôi sẽ chạy "dây" trên các hệ thống Unix nó xuất hiện trong danh sách .. không tốt.

Cách dễ nhất có thể để thay thế nó là gì? Hàm nằm trong thư viện và tôi muốn giữ nó linh hoạt. Bây giờ tôi bắt đầu mallocing trong hàm và chuỗi trong chuỗi biến mất. Tuy nhiên, khi nào tôi sẽ giải phóng nó một lần nữa?

char * getMyPassword() 
{ 
unsigned char arr[] = { 'p', 'a', 's', 's', 'w', 'o', 'r' , 'd', '\0' }; 
char *return_arr = malloc(sizeof(arr)); 
strcpy(return_arr, arr); 
return return_arr; 

} 

Nếu tôi định vuốt trước và vượt qua con trỏ, thì làm sao tôi biết kích thước trước khi kích thước mật khẩu chỉ được biết trong hàm?

Là một kế hoạch B tôi có thể vượt qua một mảng lớn, nhưng điều đó có vẻ không phải là rất thanh lịch. Làm thế nào tôi nên tiếp cận điều này?

EDIT: Tôi đã thêm strcpy (return_arr, arr). Tôi thực sự đã có nó trong mã ban đầu, nhưng quên nó ở đây.

+0

Đặt trong đó lùi, sau đó sử dụng '' 'strrev()' ''. Hoặc, rot-13 nó hai lần. –

+6

Nếu bạn định sử dụng mật khẩu, tôi khuyên bạn nên sử dụng mật khẩu được băm thay vì chuỗi chữ. Điều đó chắc chắn sẽ làm giảm lượng thông tin mà ai đó có thể có được bằng cách chạy 'chuỗi' trên chương trình. Bạn có thể tùy chỉnh hàm băm để mọi người không thể (hoặc ít nhất là khó khăn hơn nhiều) xác định giá trị thực sự là gì. – dbeer

+0

Để sử dụng mật khẩu nào?Đăng nhập ở đâu đó hoặc như vậy? –

Trả lời

2

Vấn đề bảo mật sang một bên, những gì bạn đang cố gắng làm là cấp phát bộ đệm động.

Bạn có thể sử dụng 2 phương pháp.

  1. Luôn luôn malloc bên trong hàm của bạn và ghi lại kết quả malloced.
  2. Đi theo con đường của một số hàm thư viện chuẩn, yêu cầu người dùng đó chuyển con trỏ đến bộ đệm hợp lệ và kích thước của nó và trả lại kích thước thực sự được sao chép. Một số chức năng này cho phép vượt qua check khi bạn vượt qua bộ đệm null, chúng không cố gắng phân bổ nó, mà thay vào đó hãy trả về kích thước cần thiết để giữ cấu trúc.

Có vẻ như tôi đã thực hiện phương pháp # 1.

Đối với phương pháp # 2 sử dụng chữ ký này:

int getMyPassword(char* buffer, size_t buff_size, size_t* p_num_copied) 
{ 
    unsigned char arr[] = { 'p', 'a', 's', 's', 'w', 'o', 'r' , 'd', '\0' }; 

    if (buffer == 0) 
    { 
    *p_num_copied = sizeof(arr); 
    return SUCCESS; 
    } 

    if (buff_size < sizeof(arr)) 
    { 
    *p_num_copied = sizeof(arr); 
    return BUFFER_TOO_SMALL; 
    } 

    memcpy(buffer, arr, sizeof(arr)); 

    *p_num_copied = sizeof(arr); 

    return SUCCESS; 
} 

Advantage của phương pháp # 2 là người gọi, trong nhiều trường hợp, có thể cấp phát bộ đệm trên stack, đặc biệt là nếu bạn quảng cáo tối đa yêu cầu kích thước bộ đệm. Một ưu điểm khác là quản lý bộ nhớ hiện đã được xử lý hoàn toàn bởi máy khách. Trong thư viện mục đích chung bạn không muốn tạo một máy khách tùy thuộc vào lược đồ phân bổ bộ nhớ thư viện cụ thể.

TRÊN trả lời bình luận

Nếu bạn luôn muốn sử dụng giá trị phân bổ trong mã khách hàng của bạn, thì đây là cách tôi sẽ làm điều này:

char* clientGetPasswordFromLibrary() 
{ 
    // in our day and age it's fine to allocate this much on stack 
    char buffer[256]; 
    size_t num_copied; 

    int status = getMyPassword(buffer, sizeof(buffer), &num_copied); 

    char* ret_val = NULL; 

    if (status == BUFFER_TOO_SMALL) 
    { 
    ret_val = malloc(num_copied); 

    if (ret_val == NULL) 
    { 
     return NULL; 
    } 

    getMyPassword(ret_val, num_copied, &num_copied); 
    } 
    else 
    { 
    ret_val = malloc(num_copied); 

    if (ret_val == NULL) 
    { 
     return NULL; 
    } 

    memcpy(ret_val, buffer, num_copied); 
    } 

    return ret_val; 
} 
+0

Tôi đã từng đọc rằng đó là thực hành không tốt để malloc một cái gì đó và sau đó trả lại đó là lý do tại sao tôi luôn luôn cố gắng kiềm chế không làm điều đó. Vì vậy, cảm ơn Alex lần thứ 2 của bạn. Bạn nghĩ gì về việc vượt qua bộ đệm và sau đó phân bổ lại nó? –

+0

@Frank. Nếu trong mã khách hàng của bạn, bạn luôn luôn muốn dựa vào 'malloc', đó là tốt. Tôi sẽ chỉnh sửa câu trả lời để cho bạn thấy một ví dụ về cách tôi sẽ làm điều này. –

+0

Rất hữu ích. Cảm ơn bạn! –

2

Tôi nghĩ vấn đề ở đây là, bạn đang cố gắng trả về một con trỏ tới một biến được định nghĩa cục bộ khi bạn đang cố trả về một chuỗi như thế. Tôi mong đợi chức năng đầu tiên của bạn hoạt động, vì con trỏ trả về địa chỉ cho một chữ, đó là tĩnh thông qua việc thực hiện chương trình. Tương tự, bạn có thể khai báo biến char [] trong phạm vi cục bộ của bạn là tĩnh; để nó không nằm trong phạm vi địa phương.

Nhưng thành thật mà nói, tôi không hiểu tại sao bạn muốn một hàm trả về một con trỏ thành một chuỗi ký tự; khi bạn chỉ có thể xác định chữ bên ngoài phạm vi địa phương, nơi nó thực sự là cần thiết.

+0

Lý do là hàm nằm trong thư viện mà tôi tải động khi chạy. Tôi đang làm điều này vì hệ thống trực tiếp của tôi sử dụng mật khẩu khác với hệ thống kiểm tra. –

2

tôi có một vài ý tưởng:

  1. Store phiên bản băm của mật khẩu. Trong getMyPassword(), hủy bỏ biến và trả về nó.

  2. Lưu mật khẩu vào tệp được bảo vệ (được mã hóa, với quyền đọc chỉ cho người dùng của bạn, v.v.). Tải mật khẩu từ tệp và trở lại trong chức năng của bạn.

  3. Kết hợp 1 và 2 - lưu trữ mật khẩu được băm trong tệp được bảo vệ, giải phóng nó và trả lại.

Tất cả phụ thuộc vào mức độ an toàn của bạn.

+0

Tôi thực sự thích ý tưởng và sử dụng rot13 hasher của bạn rồi. Tôi đặt nó vào thư viện được mã hóa và nó được giải mã trong nhị phân khi cần. Tôi để nó theo kiểu mảng để đảm bảo không ai có thể sử dụng chuỗi đơn giản. Tôi muốn thử ngay bây giờ, nếu tôi có thể áp dụng các quyền khác nhau cho các thư viện cũng như không vi phạm ứng dụng hiện tại của tôi. –

1

Đó là một ít hoặc vô ích (bạn biết đấy, bất kỳ ai đảo ngược chương trình của bạn có thể lấy mật khẩu dễ dàng) tập thể dục steganography. Ví dụ: bạn có thể tăng cường bảo mật hơn một chút, thực hiện như sau:

  1. Chọn giá trị "giống" được XOR với tất cả các ký tự.
  2. Làm chức năng getMyPassword để chấp nhận ký tự đó. Bằng cách này, chức năng chủ yếu là vô ích nếu bạn không biết hạt giống.

Ví dụ: lấy giá trị 55 làm hạt giống của bạn.Bạn có thể có một cái gì đó như:

char * getMyPassword(char seed) 
{ 
const char* str = "[email protected]"; 
char *return_arr = malloc(9); /* 8+1 */ 
for (int i=0 ; i < 9 ; ++i) 
    return_arr[i] = str[i]^seed; 
return_arr[i] = 0; 
return return_arr; 
} 

và bạn phải gọi getMyPassword(55) để nhận kết quả chính xác. Tôi thề, số 55 được chọn ngẫu nhiên, và tôi không biết DDVG là gì :)

+0

Rất đơn giản và hiệu quả. cảm ơn lời khuyên của bạn Diego. Tôi có thể kết hợp nó như tôi chỉ cần thêm một has13 rot13 rất đơn giản. –

+0

Điều này quá dễ. Nếu tôi nhìn vào các biểu tượng công khai của một thư viện và thấy một hàm getMyPassword, tôi sẽ tăng gấp đôi nỗ lực của mình để tháo rời chức năng đó. Nếu sau này tôi được thưởng bằng dữ liệu khách hàng như thông tin thẻ tín dụng ... Phải có cách khác để nhận mật khẩu đó vào chương trình. Tôi sẽ mở/dev/tty sau khi bắt đầu chương trình và đọc nó từ bàn phím. Đặt nó vào một lib hoặc một tập tin cấu hình là quá không an toàn. –

0

Đối với các vấn đề an ninh, Một cách phổ biến để truyền mật khẩu một cách an toàn cho một quy trình là sử dụng môi trường. Ví dụ, nếu chương trình của bạn cuối cùng được gọi từ một trang web, bạn có thể đặt mật khẩu một lần trong các tập tin cấu hình apache an toàn (thông qua SetEnv PASSWORD "secret") và nó sẽ được chuyển xuống mọi script cgi nó chạy, và bất cứ thứ gì chúng chạy . Sau đó, trong chương trình của bạn, bạn chỉ cần nhúng getenv ("PASSWORD").

Lỗi thường gặp là chấp nhận mật khẩu trên dòng lệnh của chương trình, điều này không nên được thực hiện vì dòng lệnh có thể được truy cập bằng bất kỳ quy trình nào trong/proc. Đây là cách 'ps' có thể hiển thị những gì đang chạy ví dụ.

Ngoài ra, bạn có thể đặt cho phép chương trình của mình thực thi nhưng không thể đọc được (chương trình chmod -r + x). Vì vậy, nó có thể được chạy nhưng nội dung của nó có thể không thực sự được đọc. Luôn luôn là một ý tưởng tốt cho bất cứ điều gì trong trang web của bạn phục vụ cây để tránh phơi bày mọi thứ một cách tình cờ thông qua một lỗi cấu hình máy chủ. Cho dù điều này làm việc cho các kịch bản shell được thực hiện phụ thuộc nhưng nó sẽ làm việc cho các chương trình biên dịch.

Các vấn đề liên quan