30 de dezembro de 2010

Sua rede está bem protegida contra invasões ?

Segurança é - ou ao menos deveria ser - uma grande preocupação em empresas de todos os tamanhos. Invariavelmente, a rede das empresas costuma ser a porta de entrada mais comum para invasões de hackers e ataques de pragas virtuais. A partir de um único computador afetado, toda a rede interna pode acabar comprometida, com consequências que vão desde lentidão em sistemas até vazamento de informações sensíveis das empresas.

Por isso, é imprescindível se valer das ferramentas disponíveis para deixar essa porta menos vulnerável. O uso de firewalls, antivírus, softwares de restrição de acesso à internet, configurações específicas em roteadores e outros equipamentos da rede são medidas amplamente adotadas para aumentar a segurança. No entanto, muitas empresas negligenciam ou subestimam os riscos de uma ameaça muito mais próxima : atitudes dos seus próprias funcionários. Mesmo um funcionário bem intencionado pode infectar a rede com um virus ao abrir um email contaminado ou ao usar um pen-drive em seu computador.

Uma das reportagens mais lidas no site da ComputerWorld em 2010 aborda justamente a questão da vulnerabilidade das redes empresariais frente aos novos avanços tecnológicos. São gadgets e outras ferramentas (inclusive softwares) que no geral trazem melhorias de produtividade mas que se não forem utilizadas com bom senso podem acarretar muitas dores de cabeça. A reportagem enumera 10 brechas frequentes que compromentem a segurança da rede e dá dicas de como enfrentá-las. Reproduzo a lista de brechas e as dicas abaixo abaixo. O conteúdo original pode ser acessado neste link.

1. Flash drives (Pendrives): São, disparados, a maneira mais comum de contaminar um ambiente de rede cercado por firewalls. Baratos, portáteis e capazes de carregar muitos dados, ainda são passíveis de passear por diversas máquinas diferentes. Essas características motivaram o desenvolvimento de vírus especialmente para essa mídia. É o caso do worm Conficker, que se espalha assim que o drive é conectado na máquina. Para piorar, a maioria dos sistemas operacionais monta esses dispositivos assim que são ligados .

O que fazer? Modifique as políticas de acesso automático às novas mídias do seus sistemas operacionais.

2. Laptops, notebooks, netbook e tablets: Discretos, portáteis, munidos de sistemas operacionais completos e capazes de operar usando baterias, os gadgets têm, ainda, conexão Ethernet sem fio (alguns têm portas físicas tradicionais também), e podem se comunicar com o ambiente de rede, de subrede etc. Se estiver contaminado, pode, assim que se conectar à rede, procurar por outros participantes que possam ser infectados.

Mas os dispositivos móveis têm outra fragilidade. Mobilidade. Permitir que essas máquinas passeiem livremente para cima e para baixo enquanto carregam dados de cunho confidencial é para lá de perigoso. Sugere-se que os arquivos estejam criptografados e que sejam munidos de recursos que permitam a deleção do sistema de arquivos à distância no caso de um deles “se perder”.

Logo: limite o tipo de informação armazenada nos dispositivos móveis. Dados de login em redes VPN, DV e Wi-Fi não devem ser salvos nos sistemas. Criptografar os arquivos existentes? Sim. Já.

3. Pontos de acesso de rede: essas interfaces providenciam acesso à rede sem fio para qualquer um que queira se conectar e esteja no raio de alcance da antena. Ataques executados por wardrivers - pessoas que passam o dia em vans circulando por cidades na busca por redes abertas - têm sido cada dia mais comuns. Um rede de lojas teve seu sistema invadido dessa maneira. Os dados de transações de clientes, como números de cartões de crédito, endereços, tipo de operação etc. foram parar na mão dos criminosos. Como resultado, os danos chegaram a meio milhão de dólares.

Criptografadas ou abertas, as redes Wi-Fi são, por natureza, frágeis. Existe uma série de modalidades de ataque, que podem comprometer a rede. Mesmo conexões protegidas (WPA ou WPA2) são pouco eficazes quando uma senha robusta não lhes é atribuída.

O que fazer? Separe as redes abertas das corporativas, não dê acesso aos participantes de um ambiente ao outro. Além disso, é interessante usar recursos de autenticação complementares nas redes Wi-Fi. Permissão para determinadas MACs (identificação física do adaptador de rede e único para cada placa) é uma maneira de fazer isso.

4. Mais USB: Se pensa que os flash drives (pendrives) são os únicos dispositivos USB que podem contaminar sua rede, está redondamente enganado. Máquinas digitais, MP3 players, impressoras e até porta-retratos digitais são todos capazes de armazenar arquivos potencialmente danosos à rede. Quem nunca usou uma máquina fotográfica para transportar um arquivo do Word?

Em 2008, a BestBuy, rede de lojistas, informou que fora encontrado um vírus dentro de uma desses porta-retratos digitais, recém-chegado do fabricante.

A solução: Restringir o acesso e a entrada desses dispositivos em seu ambiente de trabalho corporativo. Deixe evidente, o tempo todo, que essas mídias não devem ser conectadas nas máquinas. Há quase três anos, o Departamento de Defesa dos EUA proíbe terminantemente a entrada de qualquer dispositivo USB em suas dependências.

5. Acesso interno: não raramente, os funcionários de empresas têm acesso a ambientes de rede delicados, cheios de arquivos importantes. Se esse for o caso, todas as opções anteriores de infecção se tornam potencialmente aplicáveis. Já viu um colaborador “emprestar” o terminal de trabalho de outro colega enquanto este saiu para almoçar? E quando um empregado pede que outro libere o acesso à rede? Essas coisas são mais comuns que se pensa.

O antídoto: Troque regularmente as senhas. Funcionários só devem ter acesso às áreas de rede que sejam essenciais para seu trabalho. Qualquer pedido de acesso complementar deve ser feito para uma equipe de TI e não a um único encarregado.

6. O trojan humano: Parecidos com a versão digital inspirada no cavalo de Tróia, esses dispositivos bípedes podem vir até as empresas disfarçados de técnicos de manutenção, de limpeza ou similar. Já foram registrados casos em que esses malfeitores conseguiram acesso às salas superprotegidas de servidores.

Talvez seja uma questão cultural, mas poucos de nós impedem a entrada de alguém devidamente identificado, mesmo que seja estranho ao ambiente de trabalho. Depois de ter a entrada garantida, a infecção do ambiente de rede pode acontecer em questão de um minuto.

Como se prevenir? Expor claramente as condições de acesso de prestadores de serviço no ambiente de trabalho e verificar as informações dadas. Jamais confie no feeling.

7. Mídias óticas: Junho de 2010. Um analista de segurança do Exército dos EUA foi preso depois de roubar e publicar informações confidenciais em círculos públicos. Fontes informam que o sujeito entrou no ambiente trazendo consigo CDs de cantores populares; tudo farsa. Uma vez sentado nas máquinas, o criminoso acessou os dados que interessavam e os gravou no “CD de música” que ouvia enquanto trabalhava. Dizem, ainda, que o rapaz assoviava os sucessos que curtia enquanto roubava os dados.

Essa forma de crime é absolutamente comum. Mídias portáteis são uma maneira de transportar informações de um lugar para outro e, às vezes, isso dá problemas. Além de os drives de CD serem usados para vazar dados, é importante lembrar que também são portas de entrada de vírus, trojans etc.

Como sair dessa? Da mesma forma que lida com os dispositivos USB: restringindo seu acesso e esclarecendo as políticas aos funcionários – constantemente.

8. A mente humana: Se muitas das opções descritas até agora têm por objetivo mitigar as ameaças que pairam sobre as redes corporativas, é absolutamente necessário lembrar que a criatividade e a capacidade da mente humana em guardar informações é quase ilimitada. Será que tem alguém de olho no que você digita quando vai realizar o login em uma rede? Onde você costuma armazenar os dados importantes? É de seu costume ler documentos confidenciais quando está esperando em aeroportos ou em um café?

Como se prevenir? A melhor saída é a prevenção. Levante a cabeça enquanto visualiza conteúdo classificado como confidencial e seja cauteloso ao entrar em redes públicas.

9. Smartphones e outros gadgets: Os celulares já não são mais como eram antigamente. Hoje em dia, carregam câmeras de alta resolução e portas de conectividade de todas as espécies e tamanhos. Os sistemas operacionais também podem dar conta de vários processos ao mesmo tempo e suportam uma vasta gama de aplicativos.

Além disso, esses dispositivos têm entrada permitida em vários ambientes corporativos em que são tratados assuntos delicados, muitas vezes estratégicos. As ameaças representadas por esses gadgets são as mesmas que se observa em laptops e notebooks.

O que impede um usuário de smartphone capturar uma imagem que revele informações importantes e transmiti-la via rede 3G?

A solução para os smartphones é mesma que serve para os dispositivos USB e às mídias óticas. Esclareça aos funcionários em que condições esses dispositivos podem entrar no ambiente corporativo.

10. E-mail: Originalmente ele serve para otimizar o fluxo de trabalho e realizar a comunicação entre pares envolvidas em um processo. Mas isso é teoria. O e-mail é muito usado para enviar e receber dados. Dados estes que podem ser anexados em uma mensagem sem que se tenha certeza da idoneidade de quem os recebe.

As caixas de entrada são, ainda , poderosas portas de entrada para viroses binárias. Se conseguirem entrar na conta de e-mail, podem roubar dados de acesso e levar a um segundo ataque, de proporções hercúleas.

Tem jeito de evitar? O nome da solução é “identificação de origem”. Atribuir uma identidade a quem enviou a mensagem, usando soluções como PGP, ou uma simples rotina de perguntas antes de enviar informações confidenciais deve dar conta da questão.

Também vale restringir o banco de dados de e-mails que podem receber mensagens a partir do serviço interno. Como sempre, educação é palavra-chave: deixe claro na organização que o uso de email deve ser feito com olhos voltados à segurança.


22 de dezembro de 2010

Detectando memory leaks em seus programas Delphi/C++ Builder

Umas das grandes discussões entre defensores das linguagens de código gerenciado (como C# e Java) e defensores das linguagens puras, isto é, não gerenciadas (como C, C++ e Delphi para Win32) é justamente a diferença mais marcante entre os dois conjuntos de linguagens : o gerenciamento da memória usada pelas variáveis e objetos nos programas.

Nas linguagens gerenciadas, o programador não precisa se preocupar em comandar a liberação da memória usada por objetos que ele tenha criado num programa pois o Garbage Collector faz isso de forma automática quando o objeto sai de escopo, ou seja, quando ele não está mais sendo utilizado. A vantagem é que sempre toda memória alocada pelo programa será devolvida ao sistema operacional quando ele terminar. A contrapartida é que haverá uma thread monitorando continuamente a execução do programa (com possível impacto em performance) além do fato de não se ter controle sobre o momento em que o destrutor do objeto será de fato chamado.

Por outro lado, nas linguagens não gerenciadas é responsabilidade do programador desalocar qualquer memória que ele tenha alocado em seu programa. Como esse é um procedimento manual, eventualmente pode escapar alguma memória sem ser devolvida, o que, em situações extremas, pode resultar até na queda do sistema operacional. Mas, este método produz programas mais rápidos e o programador tem total controle sobre o instante em que cada destrutor é invocado.

À parte a discussão sobre qual das abordagens é a melhor, os desenvolvedores C++ Builder e Delphi Win32 têm uma ferramenta para ajudá-los a depurar seus programas e encontrar eventuais falhas no gerenciamento manual de memória. O FastMM é uma biblioteca que substitui o BorlndMM.DLL, que é o gerenciador padrão dos programas feitos nessas duas linguagens. O MM no nome de ambas as bibliotecas é abreviação para Memory Manager, ou Gerenciador de Memória.

Diferente do Code Guard, o FastMM detecta apenas os memory leaks, apresentando os resultados da verificação num relatório gravado ao final da execução do seu programa. Projetos feitas em ambas as linguagens extraem melhores benefícios do FastMM se estiverem compilados para depuração. Com essa opção ligada, o gerenciador consegue apontar com precisão o local onde foi alocada uma variável que não tenha sido removida da memória.

Em C++, o processo de substituição do gerenciador é mais simples pois implica em simplesmente trocar a biblioteca BorlndMM.DLL original por aquela distribuída junto com o FastMM (ou que tenha sido compilada por você mesmo com as configurações personalizadas). A única ressalva a ser feita é que há uma opção de linkagem nos projetos C++ Builder que permitem embutir no binário final o conteúdo do gerenciador de memória, eliminando a necessidade da biblioteca externa. Por isso, substituir a biblioteca só vai funcionar se o projeto estiver compilado para usar o gerenciador dinamicamente. Na versão que eu tenho do C++ Builder, esta opção aparece na página Linker das opções de projeto e tem o nome de Use Dynamic RTL.

Em projetos do Delphi para Win32, as funcionalidades providas em BorlndMM.DLL são sempre linkadas juntas, produzindo um executável ou biblioteca sem essa dependência externa, resultando num processo de substituição um pouco mais elaborado. Neste ambiente, você terá que incluir em seu projeto o fonte do FastMM e garantir que esta unit seja a primeira a aparecer na cláusula Uses do fonte do seu projeto.

Normalmente, não é necessário fazer quaisquer alterações na configuração do FastMM para depurar um projeto. No entanto, se alguma situação exigir, as configurações dele podem ser encontradas no fonte FastMM4Options.Inc, onde há uma lista de opções ricamente comentadas (em inglês) que podem ser ligadas ou desligadas de acordo com suas necessidades. As opções estão espalhadas em seções organizadas pelo tipo de efeito abordado, como por exemplo as vinculadas à melhoria do tratamento do gerenciador em projetos multi threaded (concorrência), as que controlam a forma com que os memory leaks serão reportados, as que compatibilizam o gerenciador com opções específicas do projeto e as relacionadas à depuração do seu programa quando o gerenciador está presente. Apenas lembro que o FastMM4Options.Inc é parte dos fontes do FastMM e que as alterações introduzidas nele exigem que se recompile o projeto para que surtam efetivamente os efeitos desejados.

O FastMM é um projeto open source hospedado no Source Forge, a partir de onde você pode fazer o download tanto das bibliotecas prontas para diversas versões do Delphi e do C++ Builder quanto os códigos fonte para que se possa compilar sua própria versão com um conjunto específico de opções ligadas.

Mais Informações
Site do projeto FastMM

17 de dezembro de 2010

Design Patterns em Delphi - Mediator - parte II

Dada a natureza do problema abordado pelo Design Pattern comportamental Mediator, normalmente a implementação de uma solução com ele resulta numa hierarquia de classes bastante extensa. Basta lembrar que o conceito é aplicável ao conjunto de telas (Forms) de um sistema, onde cada nova tela herdada é um mediador e os componentes inseridos nela podem conversar entre si de maneiras específicas, sem que as classes de componentes necessitem ter conhecimneto umas das outras. O conceito do Mediator foi introduzido num post em novembro, acessível neste link. Apenas para relembrar o básico: o Mediator propõe centralizar em uma única classe base a responsabilidade pela comunicação de todas as outras envolvidas na solução de um problema.

Isto posto, pretendo mostrar aqui a implementação de um exemplo simples, proposto naquele post inicial. É o exemplo da torre de controle de tráfego aéreo, onde a comunicação entre os participantes pode ser implementada de uma forma mais genérica, fazendo com que seja necessária apenas uma herança do mediador. Segue uma reprodução do diagrama UML com o exemplo proposto:
Diagrama UML para o padrão Mediator
Começo a codificação pela interface que estabelece as regras de mediação, isto é, o próprio Mediator. Ela é normalmente assentada como uma classe abstrata a partir da qual todas as possibilidades de mediação são herdadas.
TWFila = class
public
procedure push (obj: TObject);
function pop : TObject;
end;

TWAeronaveAbstrata = class;

TWTorreAbstrata = class
public
procedure concedePermissao(Aeron: TWAeronaveAbstrata); virtual;abstract;
procedure solicitaPouso (Aeron: TWAeronaveAbstrata); virtual;abstract;
procedure solicitaDecolagem (Aeron: TWAeronaveAbstrata); virtual;abstract;
end;

TWTorreAeroportoCGN = class(TWTorreAbstrata)
protected
_FilaPista : TWFila;

public
procedure concedePermissao(Aeron: TWAeronaveAbstrata); override;
procedure solicitaPouso (Aeron: TWAeronaveAbstrata); override;
procedure solicitaDecolagem (Aeron: TWAeronaveAbstrata); override;
end;

No exemplo, há apenas uma herança mas o mais comum é ter que trabalhar com diversas delas, como no caso de se usar telas como mediadores para gerenciar a comunicação entre os elementos de interface visual presentes (os componentes da tela). A classe TWFila é apenas auxiliar, sendo usada aqui para controlar a fila de aeronaves que solicitarem algum procedimento à torre. Num projeto real, é praticamente regra que tenhamos neste ponto instâncias de classes específicas cuja comunicação será mediada, implementando regras de negócio únicas. Por causa disso, cada herança do mediador é normalmente aplicada a um único cenário predeterminado.

A declaração dos Colleagues (objetos cuja comunicação é mediada) também é bem direta:
TWAeronaveAbstrata = class
protected
_Aguardando: boolean;
_Torre: TWTorreAbstrata;
public
constructor Create (ATorre: TWTorreAbstrata);

function aguardarPermissao : boolean; virtual;abstract;
procedure pousar; virtual;abstract;
procedure decolar; virtual;abstract;
procedure liberarPista; virtual;abstract;
end;

TWJatoExecutivo = class(TWAeronaveAbstrata)
public
constructor Create (ATorre: TWTorreAbstrata);

function aguardarPermissao : boolean; override;
procedure pousar; override;
procedure decolar; override;
procedure liberarPista; override;
end;

O único ponto importante a ressaltar é a existência do membro _Torre, que é uma instância da classe mediadora. Isso reforça o conceito de que a comunicação entre os diversos tipos de Colleagues deve ser levada a cabo exclusivamente através do mediador, isto é, nenhum Colleague deve ter conhecimento da existência dos demais. Como estas classes são fracamente acopladas, podemos introduzir novos Colleagues sem prejuízo para as heranças já estabelecidas na solução.

O trecho abaixo mostra um exemplo da comunicação usando o mediador.
procedure TWJatoExecutivo.pousar;
begin
{ Solicita autorização à torre e aguarda permissão }
_Aguardando := true;
_Torre.solicitarPouso ();

While (aguardarPermissao() ) do
Sleep (1000);

{ Com a permissão concedida, a pista é liberada para o procedimento da aeronave seguinte }
liberarPista;
end;

Este é um exemplo bastante simples, com as instâncias das classes do tipo Colleague inseridas numa fila. De novo : no mundo real, teríamos instâncias específicas dessas classes enviando mensagens umas às outras. Por fim, as classes representando aeronaves são muito parecidas entre si e, por isso, inclui neste post a declaração de apenas uma delas, omitindo as demais.

15 de dezembro de 2010

Criando Esquema para validar um XML - parte III

A sintaxe para criação de esquemas XSD é bem mais flexível e poderosa do que os exemplos que mostrei no último post sobre esse assunto. Para tornar mais realista o exemplo da carga de produtos mostrado lá, podemos melhorá-lo agregando novas regras.

O defeito mais patente naquele exemplo é o fato de que apenas um produto por vez pode ser incluído no XML. Numa carga, faz mais sentido aceitar que se informem diversos itens de uma só vez. Como também não é permitido a um XML ter mais de um elemento como raiz, vou acrescentar uma nova raiz - produtos - e reconfigurar a tag de produto:
<xs:element name="produtos">
<xs:complexType>
<xs:sequence>
<xs:element name="produto" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="codigo" type="xs:string"/>
.
.
.
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>

Os atributos minOccurs e maxOccus aplicados ao elemento produto determinam as quantidades mínima e máxima que esse elemento pode aparecer no XML. Caso esses atributos sejam omitidos, eles assumem o valor 1 (um); por isso, omití-los obriga sempre uma ocorrência do elemento. Valores válidos para esses atributos são números inteiros mas no caso do maxOccus podemos informar ainda o texto "unbounded" para indicar que não há limite máximo de ocorrências para o elemento. O trecho de XSD acima exemplifica ainda elementos complexos aninhados uns dentro dos outros, isto é, eles não precisam ser formados apenas por elementos simples.

O minOccurs também aceita o valor 0 (zero), o que na prática significa que o elemento em questão poderá ser omitido do XML - e, ainda assim, ele permanecerá válido. Isso abre a possibilidade de atribuirmos valores padronizados para elementos que não apareçam no XML.
<xs:element name="saldo" type="xs:decimal" minOccurs="0" default="0"/>

No caso acima, se o elemento com o saldo do item não estiver presente no XML, devemos assumir que seu valor é zero.

Os tipos de dados com os quais definimos elementos no XSD constituem um tipo de restrição aos valores que esses elementos podem assumir no XML. No entanto, há situações em que só o tipo não é suficiente para determinar a validade de um dado. Para atender essa necessidade, um esquema XSD dispõe da tag xs:restriction, que, como o nome diz, serve para criar outras restrições aos valores permitidos em elementos simples num XML. A forma mais básica de restrição é a que estipula uma faixa de valores válidos:

<xs:element name="deposito" >
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="99"/>
</xs:restriction>
</xs:simpleType>
</xs:element>

O trecho acima reformula o elemento deposito para que ele aceite apenas códigos entre 1 e 99, sendo que esses valores-limites também são válidos. Repare que, apesar de continuar a ser um elemento simples (não são definidos elementos internos nele), o tipo do deposito agora foi passado para uma estrutura interna, delimitada por uma tag xs:simpleType, dentro da qual são explicitadas as novas restrições. Outros parâmetros válidos para configurar restrições podem ser encontrados neste link.

Outro tipo de restrição bastante comum é a lista de valores permitidos. Ou seja, para o XML ser válido, o valor do elemento nele tem que ser um daqueles listados na tag de restrição do XSD:
<xs:element name="unidade" maxOccurs="5">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="UN"/>
<xs:enumeration value="CX"/>
<xs:enumeration value="KG"/>
<xs:enumeration value="PC"/>
</xs:restriction>
</xs:simpleType>
</xs:element>

Como está exemplificado acima, cada item da lista de possíveis valores é definido através de uma tag xs:enumeration. Obviamente, os valores especificados na lista devem estar de acordo com o tipo base atribuído ao elemento - no caso apresentado acima, devem ser cadeias de caracteres (strings). Vale a pena ressaltar também que letras maiúsculas e minúsculas são consideradas diferentes e isso deve ser respeitado na hora de criar as declarações. Por exemplo, de acordo com os critérios do XSD acima, um valor un ou kg no elemento unidade do XML torna-o inválido visto que está prevista apenas a ocorrência desses valores em letras maiúsculas.

Alguns campos podem apresentar restrição de tamanho para serem válidos. No ERP da ABC71, por exemplo, a descrição de um produto deve ter no máximo 50 caracteres. Uma declaração para contemplar esse tipo de restrição pode ser feita como segue:
<xs:element name="descricao">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
</xs:element>

Além de maxLength e minLength - que definem uma faixa válida de quantidade de caracteres - há o elemento length, que serve para forçar uma quantidade exata de caracteres. Não a usei no exemplo porque isso obrigaria a colocar espaços em branco após as descrições de produto até que todos eles tivessem a quantidade exata exigida.

Há uma outra forma de restrição onde podemos estipular padrões de preenchimento dos campos, padrões estes baseados em máscaras mais ou menos como nas expressões regulares. Volto em outro post para falar sobre isso.

Mais Informações
Criando esquema para validar um xml - parte I e parte II, Elemento xs:restriction

6 de dezembro de 2010

Criando Esquema para validar um XML - parte II

Depois de montar o cabeçalho do Esquema XSD, onde definimos um namespace e outros parâmetros para evitar choque de nomes com outros esquemas, podemos abordar a criação das regras de validação que orientarão como os elementos do XML devem ser criados.

Elementos são definidos num XSD usando-se a tag xs:element, que deve ser inserida entre a abertura e o encerramento da tag de cabeçalho. Um XSD pode definir basicamente dois tipos de elementos para o XML: os que contêm outros elementos aninhados são chamados de Complexos; os demais são chamados de Simples. O nó raiz do XML necessariamente será do tipo Complexo já que sempre haverão outros elementos aninhados nele.

Fica mais fácil trabalhando com um exemplo. Suponha, então, que estamos estabelecendo a estrutura de um XML a ser usado para carga do cadastro de produtos. Neste XML, as informações básicas do produto podem ser definidas no XSD como elementos simples. Segue um trecho extraído do XSD com essas definições:
<xs:element name="codigo" type="xs:string"/>
<xs:element name="deposito" type="xs:integer"/>
<xs:element name="saldo" type="xs:decimal"/>
<xs:element name="data_criacao" type="xs:date"/>

As linhas acima definem 4 elementos simples que devem aparecer no XML de produtos. A cada elemento é atribuído um nome e um tipo de dado - por enquanto, usei apenas tipos preestabelecidos pela W3C. Assim, o XML será considerado inválido se um elemento com qualquer outro nome estiver inserido nele ou se o tipo de dado esperado para cada elemento não corresponder à definição. O trecho de XML reproduzido abaixo está em conformidade com o XSD anterior:
<abc:codigo>000.001-8</abc:codigo>
<abc:deposito>1</abc:deposito>
<abc:saldo>220.34</abc:saldo>
<abc:data_criacao>2010-01-20</abc:data_criacao>

Os tipos complexos do XSD encapsulam declarações como as que fizemos no início deste post. Ao fazer isso, estabelecem também qual a sequência em que os elementos devem estar inseridos no XML. Declarar um elemento do tipo complexo exige o uso de duas novas tags: o xs:complexType - que substitui o atributo "type" usado para declarar os tipos simples - e o xs:sequence - que vai embutido no complexType e que encorpora as declarações dos demais elementos que compõem esse tipo complexo. Veja como fica a declaração do XSD para o exemplo do produto:
<xs:element name="produto">
<xs:complexType>
<xs:sequence>
<xs:element name="codigo" type="xs:string"/>
<xs:element name="deposito" type="xs:integer"/>
<xs:element name="saldo" type="xs:decimal"/>
<xs:element name="data_criacao" type="xs:date"/>
</xs:sequence>
</xs:complexType>
</xs:element>

Repare que a tag inicial é do tipo xs:element pois estamos definindo um novo elemento, ainda que do tipo complexo. O atributo name também é exigido aqui, enquanto o type foi eliminado para permitir que a declaração dos elementos seja feita de forma aninhada. O exemplo mostra apenas elementos de tipo simples aninhados no tipo complexo mas isso não é uma obrigação. Se for necessário, podemos aninhar outros tipos complexos também.

Como não estabelecemos nenhuma regra extra, todos os elementos definidos no nosso XSD tem que aparecer uma e somente uma vez no XML, isto é, esses elementos não podem ser omitidos nem aparecer duplicados. Caso contrário, o XML será considerado inválido.

Além disso, da forma como está declarado neste post, o XSD permite que apenas um produto seja incluído no XML. Num post futuro eu avanço no assunto, introduzindo novos conceitos para melhorar a declaração de tipos e enriquecer as validações, tornando-as mais precisas.