Ir para o conteúdo

Práticas Seguras de Código

📋 Visão Geral

Práticas seguras protegem contra vulnerabilidades, vazamento de dados e acessos não autorizados.


🔐 Princípio do Menor Privilégio

Dar apenas autorizações necessárias.

✅ Correto

AUTHORITY-CHECK OBJECT 'V_VBAK_VKO'
  ID 'VKORG' FIELD '1000'  " ✅ Específico
  ID 'ACTVT' FIELD '03'.   " ✅ Apenas visualizar

❌ Incorreto

" ❌ Wildcards demais
ID 'VKORG' FIELD '*'
ID 'ACTVT' FIELD '*'

🛡️ Validar Sempre Inputs

✅ Validação Completa

PARAMETERS: p_kunnr TYPE kunnr.

START-OF-SELECTION.
  " Validar formato
  IF p_kunnr IS INITIAL OR strlen( p_kunnr ) <> 10.
    MESSAGE 'Customer ID inválido' TYPE 'E'.
    RETURN.
  ENDIF.

  " Validar existência
  SELECT SINGLE @abap_true FROM kna1
    WHERE kunnr = @p_kunnr
    INTO @DATA(lv_exists).

  IF sy-subrc <> 0.
    MESSAGE |Cliente { p_kunnr } não existe| TYPE 'E'.
    RETURN.
  ENDIF.

  " Validar autorização
  AUTHORITY-CHECK OBJECT 'F_KNA1_GEN'
    ID 'KUNNR' FIELD p_kunnr
    ID 'ACTVT' FIELD '03'.

  IF sy-subrc <> 0.
    MESSAGE 'Sem autorização' TYPE 'E'.
    RETURN.
  ENDIF.

  " Processar
ENDMETHOD.

🚫 Nunca Hardcodear Credenciais

❌ Ruim

" ❌ NUNCA fazer isso!
DATA: lv_user TYPE string VALUE 'ADMIN',
      lv_pass TYPE string VALUE 'Password123'.

CALL FUNCTION 'RFC_CONNECTION'
  EXPORTING
    username = lv_user
    password = lv_pass.

✅ Bom

" ✅ Usar Secure Store
CALL METHOD cl_sec_sxml_writer=>get_instance
  RECEIVING
    r_instance = DATA(lo_sec_store).

lo_sec_store->get_credentials(
  IMPORTING
    ev_username = DATA(lv_user)
    ev_password = DATA(lv_pass) ).

🔒 Proteger Dados Sensíveis

Logs e Mensagens

" ❌ Expor senha em log
WRITE: / |Login: { lv_user } / { lv_password }|.

" ✅ Ocultar dados sensíveis
WRITE: / |Login: { lv_user } / ********|.

Não Logar Dados Pessoais (GDPR)

" ❌ Logar CPF/Email completo
MESSAGE |Processando CPF { lv_cpf }| TYPE 'I'.

" ✅ Mascarar
DATA(lv_masked) = |{ lv_cpf(3) }.***.***-**|.
MESSAGE |Processando CPF { lv_masked }| TYPE 'I'.

🔐 Sessões e Timeouts

" Verificar timeout de sessão
IF sy-datum > lv_session_date + 1 OR
   sy-uzeit > lv_session_time + 3600.  " 1 hora

  MESSAGE 'Sessão expirada. Faça login novamente.' TYPE 'E'.
  LEAVE PROGRAM.
ENDIF.

🛡️ Proteção contra Ataques

SQL Injection (ver página dedicada)

" ✅ Usar @-escaping
SELECT * FROM kna1
  WHERE kunnr = @lv_customer  " ✅ Seguro
  INTO TABLE @DATA(lt_customers).

Command Injection

" ❌ Perigoso
DATA(lv_command) = |rm -rf { lv_path }|.
CALL 'SYSTEM' ID 'COMMAND' FIELD lv_command.

" ✅ Validar input
IF lv_path CA '/\*?<>|'.
  MESSAGE 'Caracteres inválidos no path' TYPE 'E'.
  RETURN.
ENDIF.

📋 Auditoria e Logging

Logar Operações Críticas

METHOD delete_customer.
  " Verificar autorização
  AUTHORITY-CHECK OBJECT 'F_KNA1_DEL'
    ID 'KUNNR' FIELD iv_customer
    ID 'ACTVT' FIELD '06'.

  IF sy-subrc <> 0.
    " Logar tentativa falhada
    CALL FUNCTION 'BAL_LOG_MSG_ADD'
      EXPORTING
        i_s_msg = VALUE #(
          msgty = 'E'
          msgv1 = |User { sy-uname } tentou deletar { iv_customer }| ).

    MESSAGE 'Sem autorização' TYPE 'E'.
    RETURN.
  ENDIF.

  " Logar sucesso
  DELETE FROM kna1 WHERE kunnr = iv_customer.

  CALL FUNCTION 'BAL_LOG_MSG_ADD'
    EXPORTING
      i_s_msg = VALUE #(
        msgty = 'I'
        msgv1 = |Cliente { iv_customer } deletado por { sy-uname }| ).
ENDMETHOD.

🔐 Criptografia

Dados Sensíveis

" Criptografar senha antes de gravar
DATA(lo_encryptor) = cl_sec_sxml_writer=>create( ).

lo_encryptor->encrypt(
  EXPORTING
    plaintext  = lv_password
  IMPORTING
    ciphertext = lv_encrypted_password ).

INSERT INTO ztab_credentials VALUES
  ( user = lv_user password = lv_encrypted_password ).

⚡ Boas Práticas

✅ Fazer

" 1. Sempre validar inputs
IF p_input IS INITIAL OR p_input CA '*?/\'.
  MESSAGE 'Input inválido' TYPE 'E'.
ENDIF.

" 2. Verificar autorizações ANTES de processar
AUTHORITY-CHECK ...
IF sy-subrc = 0.
  " Processar
ENDIF.

" 3. Usar parametrized queries
SELECT * FROM kna1
  WHERE kunnr = @lv_customer  " ✅

" 4. Logar operações críticas
CALL FUNCTION 'BAL_LOG_MSG_ADD' ...

" 5. Timeout de sessões
IF session_expired( ).
  LEAVE PROGRAM.
ENDIF.

" 6. Mascarar dados sensíveis em logs
lv_masked = mask_cpf( lv_cpf ).

❌ Evitar

" 1. Hardcodear credenciais
DATA: lv_pass VALUE 'admin123'.  " ❌

" 2. SQL dinâmico sem validação
DATA(lv_sql) = |SELECT * FROM { lv_table }|.  " ❌

" 3. Expor dados sensíveis
WRITE: / lv_credit_card.  " ❌

" 4. Não validar input
SELECT * WHERE name = p_name.  " ❌ E se p_name = "'; DROP TABLE--"?

" 5. Confiar apenas em UI
" ❌ SEMPRE validar no backend também

" 6. Não logar operações críticas
DELETE FROM important_table.  " ❌ Sem log!

🎓 Checklist de Segurança

[ ] Autorizações verificadas antes de operações
[ ] Inputs validados (formato, range, existência)
[ ] Dados sensíveis NÃO em logs
[ ] Credenciais em Secure Store, não hardcoded
[ ] SQL parametrizado (@-escaping)
[ ] Operações críticas logadas
[ ] Timeouts de sessão implementados
[ ] Dados criptografados quando necessário
[ ] Erro handling sem expor detalhes internos
[ ] Code review de segurança realizado

🔗 Próximos Passos


Tags: #Secure-Coding #Best-Practices #GDPR #Encryption