Aumentando a segurança com LBAC - Label Based Access Control

Versão para impressãoEnviar para amigoVersão PDF

LBAC é um modo de controle de acesso. Ele não encripta dados, apenas faz o controle de permissões.

É um recurso de segurança baseado no modo MAC - Mandatory Access Control, que utiliza rótulos para definir níveis de segurança. Neste modo de trabalhar é possível definir hierarquias de acesso onde o usuário terá acesso apenas ao dado que esteja subordinada a sua credencial/hierarquia, salvo as exceções definidas.

Na teoria é algo bem simples de trabalhar, mas a definição de uma politica detalhada demais pode acabar complicando as coisas, deixando a administração e desenvolvimento um pouco mais complexa.
Algo muito importante, que nunca pode ser esquecido é que a utilização do LBAC não substitui os meios de permissões já utilizado no banco de dados através do grant/revoke (DAC - Discretionary Access Mode), ou seja, ele apenas adiciona mais uma camada de segurança.

Este recurso é disponível a partir da versão 11 e apenas para Enterprise Edition e Developer.

Este artigo irá tratar apenas do conceito e características, em breve irei postar exemplos para ilustrar tudo que foi explicado aqui.
Tentarei descreve-lo e exemplifica-lo do modo mais simples e objetivo para que não fique um artigo muito dificil de entender e muito longo.

  1. Referências
  2. DBSECADM - Database Security Administrator
  3. A Estrutura
  4. O Conceito de funcionamento
    1. Entendendo o exemplo Nivel_A
    2. Entendendo o exemplo Nivel_B
    3. Entendendo o exemplo Nivel_C
    4. Regras de acesso
  5. Definindo a politica de segurança
  6. Exemplos X Comandos DDL
  7. Características
  8. Protegendo os dados
  9. Acesso de leitura / gravação
  10. Definindo uma credencial a um usuário
  11. Exceções
  12. Funções
  13. Inclusão de dados X Credenciais
  14. Exemplos


Referências


Para mais referência no assunto, leia estes artigos, redbooks, sites e manuais:


DBSECADM - Database Security Administrator


Para configurar o LBAC é preciso definir um usuário como o Database Security Administrator, onde apenas este usuário poderá dar ou revogar niveis de acessos aos dados e usuários. Apenas o usuário DBSA pode dar permissão de DBSECADM a um usuário e este usuário não pode ser ele mesmo.

Para definir um usuário como DBSECADM, é utilizado uma role (GRANT) interna (built-in) no banco criada para definir que um usuário possui o poder da administração da segurança LBAC. Os conceitos para esta role são as seguintes:

  • Apenas o DBSA (System Administrator) pode conceder (grant) e/ou revogar (revoke) a role DBSECADM para um usuário.
  • Para a utilização desta role basta que o usuário "possua" ela, ou seja, não é necessário ativa-la através do comando "set role".
  • O escopo desta role é para toda instancia, independente do banco para qual foi concedida.
  • O usuário que possuir o DBSECADM será o único que poderá: Criar LBAC (components, polices, label), proteger tabelas com LBAC, conceder acesso de LBAC a usuários e isenção (exceções) de acessos LBAC a usuários.

A Estrutura


Para definir uma politica de segurança, primeiro você precisa montar a estrutura dos rótulos e seus níveis (credenciais) .
  1. Necessário definir com quais os componentes (tipos de níveis) irá trabalhar
    Nivel_A: Secreto, Confidencial, Administrativo, Publico
    Nivel_B: Recursos-Humanos, Financeiro, Compras, Vendas, Produção
    Nivel_C: Matriz-Brasil, Regional-SP, Filial-Jundiai/SP, 
                    Filial-Bauru/SP, Regional-RJ, Filial-Rezende, Filial-Niterói
    

  2. Definir a politica de segurança, especificando quais niveis de segurança farão parte:
    Politica EmpresaX: Utiliza Nivel_A e Nivel_C
    Politica EmpresaY: Utiliza Nivel_A, Nivel_B e Nivel_C
    

  3. Criar os rótulos de segurança / credenciais
    Estes rótulos são as credenciais, os níveis de segurança efetivamente aplicados aos dados e usuários:
         Rótulo
    =======================
    EmpresaX.diretorSP  = Nivel_A.Confidencial   + Nivel_C.Regional-SP
    EmpresaX.diretorRJ  = Nivel_A.Confidencial   + Nivel_C.Regional-RJ
    EmpresaX.Presidente = Nivel_A.Secreto        + Nivel_C.Matriz-Brasil
    EmpresaX.Gerente    = Nivel_A.Administrativo + Nivel_C.Filial-Jundiai/SP
    EmpresaX.operador   = Nivel_A.Publico        + Nivel_C.Filial-Jundiai/SP
    
    EmpresaY.diretorSP  = Nivel_A.Confidencial   + Nivel_B.* 
                                 + Nivel_C.Regional-SP
    EmpresaY.diretorRJ  = Nivel_A.Confidencial   + Nivel_B.* 
                                 + Nivel_C.Regional-RJ
    EmpresaY.Presidente = Nivel_A.Secreto        + Nivel_B.* 
                                 + Nivel_C.Matriz-Brasil
    EmpresaY.Gerente    = Nivel_A.Administrativo + Nivel_B.Financeiro 
                                 + Nivel_C.Filial-Jundiai/SP
    EmpresaY.operador   = Nivel_A.Publico      + Nivel_B.Produção     
                                 + Nivel_C.Filial-Jundiai/SP
    

  4. Associar estas credenciais aos usuários e dados através de GRANT e CREATE/ALTER TABLE


O Conceito de funcionamento


Olhando os passos explicados anteriormente, você deve estar se perguntando qual é a lógica utilizada para cada um destes *tipos* de níveis no momento de validar a segurança de um usuário ao dado. Abaixo explico uma a uma.

Entendendo o exemplo Nivel_A


Este nível é uma lista (ARRAY) onde sua principal característica é a ordem que os dados são declarados.
Nele o primeiro item é o de nível mais alto e o ultimo item o de nivel mais baixo.
O dado e o usuário deverá estar relacionado a apenas um único item desta lista.

Um usuário que está associado a um nível X não terá acesso de *leitura* a um dado associado ao nível imediatamente superior mas terá acesso a todos os dados associados aos níveis igual ou inferior ao dele.
Para gravação o usuário obrigatóriamente precisa ter o mesmo nível que o dado, mesmo que ele possua um nível de acesso superior não será permitido que ele altere o dado (a não ser que seja definido uma exceção, mas veremos sobre exceções mais ao final do artigo).

Neste tipo de controle de acesso você pode utilizar para situações como :
  • Nível de importância da informação (secreto a publico)
  • Nível de cargos de funcionários (presidente a operador)

Entendendo o exemplo Nivel_B


Este nível é um conjunto (SET), igual a que utilizamos em matemática. O dado e usuário deverá estar relacionado a um ou mais item(ns), formando assim o seu próprio conjunto de itens. Nele não há distinção de item com nível mais alto ou mais baixo.
Para acesso de leitura ao dado o usuário deverá possuir em sua credencial no mínimo o conjunto de todos os itens definidos para o dado. Se faltar um único item o acesso não será autorizado.
Para gravação utiliza-se a mesma lógica da leitura.

Neste tipo de controle de acesso você pode utilizar para situações como :
  • Regionalização de um assunto ( Assuntos_internos, Relações_Publicas, etc).
  • Setorização de uma empresa (Atendimento, Vendas, Producao, etc).

Entendendo o exemplo Nivel_C


Este nível trabalha como diretórios/arvore (TREE), permitindo várias ramificações de pais e filhos.
O funcionamento dele é similar ao do exemplo Nivel_A, mas com uma diferença crucial, os níveis de acesso superior a um item é apenas aqueles ligado a sua ramificação (parentesco) e apenas um item está relacionado ao usuário/dado.
Para acesso de leitura ao dado o usuário deverá ter em sua credencial um item igual ou que seja um dos pais do nivel de segurança do dado.
Para gravação utiliza-se a mesma lógica da leitura

Neste tipo de controle de acesso você pode utilizar para situações como :
  • Setorização de uma empresa (Diretoria_producao é pai de produção,estoque e expedição)
  • Regionalização de empresa (Matriz é pai de filiais que são pais de postos avançados)
  • Hierarquias em um assuntos específicos

Regras de acesso


Para cada um destes três tipos de componentes (ARRAY, SET e TREE) existe uma regra de acesso de leitura e gravação, que nada mais é do que foi explicado nos três ultimos itens.
Mas estes acessos possuem uma nomenclatura que são utilizadas indiretamente nos GRANT/REVOKE das credenciais e diretamente/explicitamente nas exceções aos usuários.
O nome destas regras são:
Para leitura: IDSLBACREADARRAY,  IDSLBACREADSET,   IDSLBACREADTREE
Para gravação: IDSLBACWRITEARRAY, IDSLBACWRITESET,  IDSLBACWRITETREE 

Você utilizará estes nomes nos comandos SQL/DDL para conceder ou revogar exceções (através do GRANT).


Definindo a politica de segurança


A definição da politica de segurança é a configuração de um ou mais tipos de niveis de acesso. Deste modo você pode mesclar vários meios de restringir o acesso ao dado.
Nos exemplos já passados, você pode ver que há politica que utiliza o tipo Nivel_A + Nivel_C , assim para que um usuário tenha acesso a informação é obrigatório que sua credencial passe por estas duas verificações, a não ser que ele possua alguma exceção definida.

Para as tabelas, nos niveis de acesso por coluna e/ou registro é permitido trabalhar com apenas uma única politica.

Apesar de no exemplo que descrevi utilizar uma única politica de segurança para uma empresa inteira, você pode ter mais de uma politica de segurança para o mesmo banco de dados, onde certas tabelas seguem uma politica enquanto outras tabelas seguem outras politicas. Assim como um usuário pode possuir mais de uma politica de segurança, você terá um ambiente extremamente flexível (e complexo).

Por exemplo, pode-se ter uma politica de segurança para o Recursos Humanos, outra para Vendas e outra para demais setores. Cada usuário terá seu nível de acesso especifico para cada politica, sendo presidente em uma politica e um simples operador para outra politica.


Exemplos X Comandos DDL


Aqui irei descrever os comandos do LBAC, com valores similares dos exemplos teóricos já citados.
Os comandos para definição do LBAC segue a mesma estrutura dos exemplos, mas utilizando a seguinte nomenclatura: Components, Policy e Labels
COMPONENTS / COMPONENTE
 Tipo do nível de segurança. Pode ser: ARRAY , SET ou TREE.

 CREATE SECURITY LABEL COMPONENT lbac_cpm_nivel
   ARRAY [ 'secreto','confidencial','administrativo','publico' ] ;
 CREATE SECURITY LABEL COMPONENT lbac_cpm_setor
   SET { 'comercial','rh','atendimento','diretoria','compras' } ;
 CREATE SECURITY LABEL COMPONENT lbac_cpm_filiais
   TREE ( 'matriz' ROOT
          ,'controladora_brasil' under 'matriz'
          ,'filial_sp' under 'controladora_brasil'
          ,'filial_rj under 'controladora_brasil'
          ,'controladora_argentina' under 'matriz'
          ,'filial_buenos' under 'controladora_argentina'
          ,'filial_bariloche' under 'controladora_argentina'
       )

POLICY / POLITICA DE SEGURANÇA
 É o conjunto de COMPONENTES, onde é definido a politica de segurança

 CREATE SECURITY POLICY lbac_pol COMPONENTS lbac_cpm_nivel
 CREATE SECURITY POLICY lbac_empresax COMPONENTS lbac_cpm_nivel, 
   lbac_cpm_filiais
 CREATE SECURITY POLICY lbac_empresay COMPONENTS lbac_cpm_nivel, 
   lbac_cmp_setor, lbac_cmp_filiais

LABEL / ROTULO
  É a credencial em si, onde é especificado qual o nivel de segurança 
  ela permite ter acesso.
  Um label é utilizado para um usuário e para os dados.

  CREATE SECURITY LABEL lbac_pol.diretor COMPONENT 
    lbac_cpm_nivel 'secreto' ;
  CREATE SECURITY LABEL lbac_empresax.presidente COMPONENT 
    lbac_cpm_nivel 'secreto' , lbac_cmp_filiais 'matriz' ;
  CREATE SECURITY LABEL lbac_empresax.diretor_sp COMPONENT 
    lbac_cpm_nivel 'confidencial' , lbac_cmp_filiais 'filial_sp' ;
  CREATE SECURITY LABEL lbac_empresax.operador COMPONENT 
    lbac_cpm_nivel 'publico' , lbac_cmp_filiais 'filial_buenos' ;


Características


Antes de dar continuidade é bom citar as características gerais do LBAC.
  • O LBAC não realiza encriptação de dados, apenas faz controle no acesso.
  • Ao um usuário sem credencial acessar uma tabla protegida por linha, nenhum erro será retornado e nenhum registro também. Se a proteção for por coluna o usuário não poderá fazer referencia a esta coluna, se o fizer será retornado erro.
  • Uma tabela protegida pelo LBAC só pode ser protegida por apenas uma politica de segurança.
  • Ao proteger uma tabela *já existente*, proteção por linha (ALTER TABLE), é obrigatório especificar no valor DEFAULT (credencial padrão) para os dados já existentes. Mas este valor padrão não permanece para novas inclusões. Quando protegida por coluna, no próprio comando de definição é especificado o valor DEFAULT (credencial padrão) e este valor é fixo para todos os dados naquela coluna, não sendo possivel informar qual credencial será gravada.
  • Uma tabela protegida por linha, não pode ter valor NULO no campo de identificação do rótulo (credencial).
    Sendo assim, na inclusão de dados é obrigatório que o usuário utilize uma função para especificar qual credencial será aplicada.
  • A credencial de um usuário é dividia em leitura e gravação, estas credenciais podem ser diferentes.
    Exemplo: Para leitura credencial de diretor, para gravação credencial de operador.
  • Um usuário pode possuir apenas a credencial de leitura ou apenas a de gravação.
  • Um usuário pode "participar" de várias politicas de segurança, mas é limitado a duas credenciais para cada politica de segurança
    Estas duas credenciais são referente a leitura e gravação na mesma politica de segurança.
  • Um usuário que não possui nenhuma credencial de segurança não pode accessar uma tabela/linha/coluna protegida.
    Mas se este usuário possuir exceção definida ele poderá ter acesso a leitura e gravação
  • Para inclusão em tabelas com controle de acesso por linha:
    • Credenciais que possuem componente do tipo ARRAY, o usuário não pode salvar uma informação com credencial diferente da que ele possui, mesmo que seja para um nível mais baixo
      Mas se este usuário possuir exceção definida, dependendo do tipo de exceção, isto é possível.
    • Para credenciais que possuem componente do tipo SET, o usuário pode salvar uma informação com credencial em qualquer combinação, desde que ele possua acesso a todas credenciais utilizadas.
    • Para credenciais que possuem componente do tipo TREE, o usuário pode salvar uma informação com credencial inferior ou igual a que ele possui, respeitando a limitação de parentesco (pai,filho).
  • Nome da credencial (rótulo, security label), é sempre minusculo, principalmente quando descrito de modo literal (entre aspas).
    Mas o nome de seus itens (descrito entre aspas) são sensiveis a caixa-alta (case sensitive)
  • IMPORTANTE: A gravação de identificação da credencial ao incluir/atualizar um dado é feita a nível do componente e não do nome da credencial.
    Deste modo, se você criar duas credenciais com niveis de acesso iguais, definir cada credencial para diferentes usuários, estes usuários conseguirão accessar os dados do outro. Se você gerar um dbschema do banco, verá que estes dois usuários terão as duas credenciais (mesmo você tendo autorizado em apenas uma).
    Pessoalmente, não consigo ver motivos lógicos para este comportamento, assim eu considero isso um bug.
  • Um usuário com grant de DBSECADM não pode dar permissões LBAC para si mesmo.
  • É possível alterar (apenas adicionar) itens nos tipos de niveis (secure label component) através do comando ALTER SECURITY LABEL COMPONENT.
  • Algumas considerações administrativas:
    • É possível renomear qualquer um dos componentes (tipo, politica, credencial), sem gerar consequencias nos dados.
    • Não é possível excluir um componente que esteja sendo utilizado em um usuário ou protegendo uma tabela.
    • As informações de qual credencial protege uma tabela/coluna e usuário ficam salvas nas tabelas SMI:
      syscolumns, sysseclabelcomponents, sysseclabelcomponentelements, syssecpolicies, syssecpolicycomponents, syssecpolicyexemptions, sysseclabels, sysseclabelnames, sysseclabelauth
    • Exportanto/importando dados com unload/load/dbload/HPL/dbimport/dbexport:
      Para todos os meios, o tratamento é igual.
      • Exportação: Será exportado apenas os dados que o usuário possuir acesso. As tabelas com linhas protegidas terão o código de interno do LBAC exportado.
      • Importação: É necessário que o usuário utilizado tenha acesso de gravação nas credenciais utilizadas nos dados.
    • Para evitar problemas é excencial trabalhar com as exceções em um usuário especifico para realizar as exportações e importações sem correr risco de faltar dados.
    • Tabelas protegidas por LBAC não são compatíveis com o ER (Enterprise Replication) e não podem ser replicadas
    • O usuário que executar o backup (ontape/onbar) da instancia precisa ter acesso a todas credenciais para realizar o backup.
    • Para qualquer tipo de manipulação em tabelas com indices, PK ou FK, a validação irá ocorrer normalmente para os registros que o usuário possui acesso. Se para uma realizar uma validação de FK o usuário precisa acessar um registro protegido, que ele não tem acesso, a validação irá falhar.
    • Usuários sem credenciais podem realizar alterações de estrutura DDL (DROP, TRUNCATE, ALTER) em tabelas protegidas.
    • Os comandos onlog e oncheck não passam por validações do LBAC, portando deve-se ter cuidado com estes comandos já que com eles é possível exibir o conteúdo de dados protegidos.
    • Mais referências no manual, aqui e aqui.
  • Uma tabela que é protegida por registro, onde é adicionado um campo do tipo IDSSECURITYLABEL, irá ocupar mais espaço e este campo é um VARCHAR(128).
    Portando, em manutenções na tabela o recurso alter in-place não funcionará.

Protegendo os dados


Para proteger um dado é preciso alterar a estrutura da tabela, sendo necessário prever o espaço adicional.
Deve-se utilizar parâmetros dos comandos ALTER TABLE para uma tabela já existente ou CREATE TABLE para uma nova tabela.
# Neste exemplo o LBAC é adicionada por coluna, na criação da tabela
create table "ix_dbsa".t_salario
  (
    user_id "ix_dbsa".dt_codigo not null ,
    salario decimal(20,2) column secured with secretario_saude
  ) security policy lbac_pol extent size 16 next size 16 lock mode row;
;

# Aqui o resultado final é igual ao exemplo anterior, mas utilizando
# o ALTER TABLE
create table t_salario (
  user_id dt_codigo not null
 ,salario decimal(20,2) not null 
)
;
alter table t_salario modify ( salario decimal(20,2) COLUMN SECURED WITH secretario_saude )
  , add security policy lbac_pol
;

# Aqui é incluido o LBAC por registro onde o nome "lbac_lab" é 
# definido por mim. O valor default é valido apenas para os registros já 
# existentes e não tem efeito para novas inclusões.

alter table t_cargo add ( lbac_lab idssecuritylabel default 'rh_saude' )
  ,add security policy lbac_pol
;


Acesso de leitura / gravação


Quando definido uma credencial para um usuário, este tem credenciais de leitura e gravação.
Não é obrigatório que o usuário possua as duas credenciais, um usuário pode ter apenas a credencial de leitura ou apenas a de gravação.
Estas credenciais não precisam necessáriamente ser a mesma, mas há algumas restrições para utilizar credenciais diferentes:
  • A credencial de leitura e gravação precisam pertencer a mesma politica de segurança
  • A credencial de gravação, não pode ter nenhum item com nível superior ao de leitura
    Isso evita situação onde um usuário não consegue ler o dado que ele mesmo gravou (porém é possível forçar esta situação através de exceções).
  • Para o componente/tipo de nível ARRAY, o item da credencial de leitura e gravação obrigatóriamente terão de ser o mesmo.


Definindo uma credencial a um usuário


Para conceder uma credencial de segurança a um usuário é um processo muito simples onde se utiliza o comando GRANT.
Para revogar uma credencial, utiliza-se o comando REVOKE.
Através do GRANT também pode condecer as exceções onde um usuário poderá acessar e escrever em dados que estão além da sua credencial.
# Concede credencial de leitura e gravação 
grant security label lbac_pol.secretario_educacao to usr1 for all access ;
grant security label lbac_pol.medico to usr3 ;

# Concede credencial de outras politicas para o mesmo usuário
grant security label lbac_pol_EmpresaX.presidente to usr1;
grant security label lbac_pol_EmpresaY.socio to usr1;

# Define diferentes credenciais para o mesmo usuário
grant security label lbac_pol.rh_educacao to usr2 for read access ;
grant security label lbac_pol.professor to usr2 for write access ;

# Revoga uma credencial de um usuário
revoke security label lbac_pol_EmpresaY.socio from usr1;

# Revoga todas as credenciais de uma politica dos usuarios 
revoke security label lbac_pol.* to usr1,usr2,usr3 for read access ;


Exceções


Há situações em que por mais flexivel seja a sua estrutura de credenciais você não conseguirá atender 100% dos casos. Assim será necessário conceder algumas exceções. A exceção permite que a verificação de um componente na politica de segurança seja *ignorado*.
Quando digo um componente, estou me referindo a um dos tipos de níveis utilizado , um array, set ou tree. Lembre-se de que é possível mesclar estes componentes em uma unica politica de segurança, sendo assim é possível permitir exceções em apenas algum deles.

A exceção pode ser concedida apenas para leitura , escrita ou ambas.

Um usuário que não possui credencial alguma pode possuir execeção completa, permitindo assim acesso a todos os dados

# Exemplos de como conceder exceções
grant exemption on rule idslbacwritearray for lbac_pol to cmartins;
grant exemption on rule all for lbac_pol to usr1;
grant exemption on rule idslbacwriteset for lbac_pol to usr2;

# Exemplos de como revogar exceções
revoke exemption on rule all for lbac_pol from cmartins;
revoke exemption on rule idslbacwritearray for lbac_pol from usr2;


Funções


Para trabalhar com LBAC existem 3 funções:
  • SECLABEL_BY_NAME: Utilizado para salvar a codificação de uma credencial em um registro protegido. Com esta função é necessário informar o nome da politica de segurança e da credêncial. Utilizado principalmente em INSERT e UPDATES.
  • SECLABEL_BY_COMP: Idem a função anterior, mas aqui o usuário irá informar diretamente os níveis de segurança(componentes que uma credencial é composta).
  • SECLABEL_TO_CHAR: Faz o caminho inverso das funções acima, retorna em formato texto o nome dos níveis que compõem uma credencial. Utilizado em SELECTs.

Inclusão de dados X Credenciais


Quando o usuário altera um dado e altera a credencial deste dado a validação de gravação da credencial é feita na credencial passada pelo comando (INSERT,UPDATE,DELETE).
Se o usuário não possuir autorização para a credencial passada no comando o banco irá retornar erro de credenciall não autorizada. É possível modificar este comportamento para que em situações como essa seja gravado automaticamente a credencial que o usuário possui (e não a passada pelo comando).
Esta definição de comportamento é feita no nível de politica de segurança.
# Utilizar o parametro OVERRIDE NOT AUTHORIZED
CREATE SECURITY POLICY lbac_pol_sigrh COMPONENTS lbac_cpm_cargo
OVERRIDE NOT AUTHORIZED WRITE SECURITY LABEL
;


Exemplos


Existe muitas situção para exemplificar e se for colocar cada um deles aqui o artigo irá ficar muito longo.
Portanto estou disponibilizando os scripts de testes que utilizei já com um alguns dados.
Com este unico script você consegue simular praticamente todas as situações mas terá que adaptar os usuários e dbspace:
  • Neste script você terá comentários como v01 e v02 onde o v01 representa as opções por ARRAY e a v02 as opções por SET.
  • O usuário "ix_dbsa" é utilizado para criar a estrutura, portanto ele possui a role DBSECADM.
  • Varios usuários são utilizados nos testes, verifique os grants.
  • Verifique o dbspace utilizado para criar o banco
  • Veja no final do script as proteções adicionadas as tabelas
  • Utilize a role r_gravacao (set role r_gravacao) em suas conexões
Script: dblbac.sql
Arquivos para carga:cargo.unl, orgao.unl, salario.unl, sal_mov.unl, user_compl.unl, user.unl

0
Ainda não votado
Sua avaliação: Nenhum

Comentar

O conteúdo deste campo é privado não será exibido ao público.
  • Endereços de páginas de internet e emails viram links automaticamente.
  • Você pode usar tags BBCode no texto.
  • Tags HTML permitidas: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>

Mais informações sobre as opções de formatação

CAPTCHA
Este teste é para bloquear programas automatizados e previnir spams
CAPTCHA de Imagem
Digite o texto exibido na imagem.