Проверка передаваемого содержимого#
Одной из основных задач SOWA является проверка пакетов, передаваемых через SOWA на соответствие схемам валидации (для структурированных данных в форматах JSON/XML), а также поиск потенциальных инъекций как в содержимом, так и в заголовках запросов и ответов.
Валидация JSON#
Подключение валидации на примере JSON сообщений.
Для начала сгенерируйте схемы для сообщений, которые нужно использовать для проверки содержимого для каждого разрешенного нами метода.
Для POST запросов это будет схема для запроса:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"data": {
"type": "string"
},
"value": {
"type": "number"
}
},
"required": [
"data"
]
}
Для GET это будет схема для ответа:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"message": {
"type": "string"
},
"result": {
"type": "number"
}
},
"required": [
"message", "result"
]
}
Создайте профиль json_validation:
[sowacfg@tkle-ish0038 proxies]$ sowa-config --add-profile json_validation
Profile "json_validation" was successfully created
Также создайте файлы postReq.json и getResp.json, в которые поместите созданные схемы.
Скопируйте данные файлы в папку /schemes, которую создайте в ресурсной папке профиля:
mkdir /sowa/profile_storage/custom/json_validation/schemes
cp schemes/postReq.json /sowa/profile_storage/custom/json_validation/schemes
cp schemes/getResp.json /sowa/profile_storage/custom/json_validation/schemes
Создайте конфигурационный файл профиля json_validation со следующим содержимым:
profile: json_validation
version: 2.0.3
system:
wrk_count: 1
conn_count: 4096
optional:
log_level: error
service:
service_http_proxy:
- id: 1
listen:
- port: 11111
url: ^/validateMe
allowed_queries:
- method: get
- method: post
validators:
validator_json:
request:
- method: post
schema: schemes/postReq.json
response:
- method: get
schema: schemes/getResp.json
upstream_group_id: back_1
upstream_groups:
- id: back_1
servers:
- server: 127.0.0.1:10025
Как видно из конфигурации, за валидацию отвечает секция валидаторов (validators), в которой определяется тип валидатора (validator_json или validator_xsd).
Внутри данных секций задаются правила валидации, которые для запросов состоят из следующих параметров:
schema — файл со схемой валидации;
method — наименование http-метода для запросов, по которому будет применяться данная схема;
params — условия проверки параметров.
Для ответов дополнительно можно задать условия на ожидаемый статус ответа, в этом случае будет осуществляться валидация ответов только для данного статуса.
response:
- method: get
schema: schemes/getResp.json
response_code:
operator: "="
pattern: "200"
То есть здесь было указано, что валидация по схеме getResp.json будет выполняться только для ответов со статусом 200. Внесите данное ограничение в конфигурацию профиля и выполните конфигурацию.
Далее, в сервисы заглушек добавьте заглушку, которая будет возвращать json-ответ.
- id: hello_json
optional:
response_code: 200
response_body: "{\"message\": \"my message\", \"result\": 0}"
response_headers:
- name: Content-Type
value: application/json
url: ^/validateMe
listen:
- port: 10025
Сконфигурируйте заглушку и запустите ее.
[sowacfg@tkle-ish0038 proxies]$ sowa-config --config ../stubs/sample_stub.yml
Profile sample_stub is running. Are you sure that you want to reconfigure? [y/n] y
Profile "sample_stub" was successfully configured.
[sowacfg@tkle-ish0038 proxies]$ sowa-config --stop sample_stub
Profile "sample_stub" was successfully stopped.
[sowacfg@tkle-ish0038 proxies]$ sowa-config --run sample_stub
Profile "sample_stub" was successfully started.
И запустите профиль json_validation.
Отправьте корректный POST-запрос:
[sowacfg@tkle-ish0038 proxies]$ curl -v --data "{"data": "data"}" http://localhost:11111/validateMe
* About to connect() to localhost port 11111 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11111 (#0)
> POST /validateMe HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11111
> Accept: */*
> Content-Length: 12
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 12 out of 12 bytes
< HTTP/1.1 200 OK
< Date: Tue, 06 Apr 2021 13:02:48 GMT
< Content-Type: application/json
< Content-Length: 38
< Connection: keep-alive
< Server: sowa
< Accept-Ranges: bytes
<
* Connection #0 to host localhost left intact
{"message": "my message", "result": 0}[sowacfg@tkle-ish0038 proxies]$
Отправьте некорректный POST-запрос:
[sowacfg@tkle-ish0038 proxies]$ curl -v --data "{"dat": "data"}" http://localhost:11111/validateMe
* About to connect() to localhost port 11111 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11111 (#0)
> POST /validateMe HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11111
> Accept: */*
> Content-Length: 11
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 11 out of 11 bytes
< HTTP/1.1 403 Forbidden
< Date: Tue, 06 Apr 2021 13:04:17 GMT
< Content-Type: application/octet-stream
< Content-Length: 30
< Connection: keep-alive
< Server: sowa
<
* Connection #0 to host localhost left intact
message: Error in request body[sowacfg@tkle-ish0038 proxies]$
Получен корректный ответ на GET-запрос:
[sowacfg@tkle-ish0038 proxies]$ curl -v http://localhost:11111/validateMe
* About to connect() to localhost port 11111 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11111 (#0)
> GET /validateMe HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11111
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 06 Apr 2021 13:05:33 GMT
< Content-Type: application/json
< Content-Length: 38
< Connection: keep-alive
< Server: sowa
< Accept-Ranges: bytes
<
* Connection #0 to host localhost left intact
{"message": "my message", "result": 0}[sowacfg@tkle-ish0038 proxies]$
Поменяйте в заглушке ответ на некорректный по схеме валидации:
- id: hello_json
optional:
response_code: 200
response_body: "{\"msg\": \"my message\", \"result\": 0}"
response_headers:
- name: Content-Type
value: application/json
url: ^/validateMe
listen:
- port: 10025
Переконфигурируйте и перезапустите профиль заглушек и отправьте запрос:
[sowacfg@tkle-ish0038 proxies]$ curl -v http://localhost:11111/validateMe
* About to connect() to localhost port 11111 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11111 (#0)
> GET /validateMe HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11111
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Date: Tue, 06 Apr 2021 13:09:25 GMT
< Content-Type: text/html
< Content-Length: 52
< Connection: keep-alive
< Server: sowa
<
<html>
<body>
Error in response body
</body>
* Connection #0 to host localhost left intact
Валидация WSDL/XSD#
В предыдущем разделе было рассмотрено, как подключить валидацию на примере JSON. Перейдем к случаю подключения валидации WSDL/XSD.
XSD определяет схему, которая является определением того, как XML-документ может быть структурирован. Существует возможность использовать его для проверки того, что данный XML-документ действителен и соответствует правилам, изложенным в схеме.
WSDL — это документ XML, описывающий веб-сервис. Он показывает, какие операции доступны и как должны быть структурированы данные для отправки этим операциям. Документы WSDL имеют связанный XSD, в котором показано, что можно поместить в документ WSDL.
Валидация по WSDL#
В данном разделе рассмотрим пример, как можно использовать wsdl схему для валидации веб-сервисов.
В каталоге proxies создайте и наполните соответствующим содержимым файлы dataset.wsdl, dataset.xsd и stringArray.xsd.
dataset.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://example.example.com/dataset" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://example.example.com/dataset" name="DataSetProviderImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://example.example.com/dataset" schemaLocation="dataset.xsd"/>
</xsd:schema>
<xsd:schema>
<xsd:import namespace="http://jaxb.dev.java.net/array" schemaLocation="stringArray.xsd"/>
</xsd:schema>
</types>
<message name="fetch">
<part name="sessionKey" type="xsd:int"/>
<part name="providerName" type="xsd:string"/>
<part xmlns:ns1="http://jaxb.dev.java.net/array" name="paramNames" type="ns1:stringArray"/>
<part xmlns:ns2="http://jaxb.dev.java.net/array" name="paramValues" type="ns2:stringArray"/>
<part xmlns:ns3="http://jaxb.dev.java.net/array" name="fieldNames" type="ns3:stringArray"/>
<part xmlns:ns4="http://jaxb.dev.java.net/array" name="indexFieldNames" type="ns4:stringArray"/>
<part xmlns:ns5="http://jaxb.dev.java.net/array" name="indexFieldValues" type="ns5:stringArray"/>
<part xmlns:ns6="http://jaxb.dev.java.net/array" name="headFields" type="ns6:stringArray"/>
<part name="rowsCount" type="xsd:long"/>
<part name="version" type="xsd:long"/>
</message>
<message name="fetchResponse">
<part xmlns:ns7="http://jaxb.dev.java.net/array" name="return" type="ns7:stringArrayArray"/>
<part xmlns:ns8="http://jaxb.dev.java.net/array" name="headFields" type="ns8:stringArray"/>
<part name="rowsCount" type="xsd:long"/>
<part name="version" type="xsd:long"/>
<part name="finished" type="xsd:boolean"/>
<part xmlns:ns9="http://jaxb.dev.java.net/array" name="deleted" type="ns9:stringArray"/>
</message>
<message name="getDataVersions">
<part name="sessionKey" type="xsd:int"/>
<part xmlns:ns10="http://jaxb.dev.java.net/array" name="paramNames" type="ns10:stringArray"/>
</message>
<message name="getDataVersionsResponse">
<part name="return" type="tns:dataVersionArray"/>
</message>
<portType name="DataSetProvider">
<operation name="fetch" parameterOrder="sessionKey providerName paramNames paramValues fieldNames indexFieldNames indexFieldValues headFields rowsCount version finished deleted">
<input message="tns:fetch"/>
<output message="tns:fetchResponse"/>
</operation>
<operation name="getDataVersions" parameterOrder="sessionKey paramNames">
<input message="tns:getDataVersions"/>
<output message="tns:getDataVersionsResponse"/>
</operation>
</portType>
<binding name="DataSetProviderImplPortBinding" type="tns:DataSetProvider">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
<operation name="fetch">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal" namespace="http://example.example.com/dataset"/>
</input>
<output>
<soap:body use="literal" namespace="http://example.example.com/dataset"/>
</output>
</operation>
<operation name="getDataVersions">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal" namespace="http://example.example.com/dataset"/>
</input>
<output>
<soap:body use="literal" namespace="http://example.example.com/dataset"/>
</output>
</operation>
</binding>
<service name="DataSetProviderImplService">
<port name="DataSetProviderImplPort" binding="tns:DataSetProviderImplPortBinding">
<soap:address location="http://example:8080/dataset"/>
</port>
</service>
</definitions>
dataset.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:tns="http://example.example.com/dataset" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://example.example.com/dataset">
<xs:complexType name="dataVersion">
<xs:sequence>
<xs:element name="cleanVersion" type="xs:long" minOccurs="0"/>
<xs:element name="filterVersion" type="xs:string" minOccurs="0"/>
<xs:element name="newVersion" type="xs:long" minOccurs="0"/>
<xs:element name="version" type="xs:long" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="dataVersionArray" final="#all">
<xs:sequence>
<xs:element name="item" type="tns:dataVersion" minOccurs="0" maxOccurs="unbounded" nillable="true"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
stringArray.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:tns="http://jaxb.dev.java.net/array" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://jaxb.dev.java.net/array">
<xs:complexType name="stringArray" final="#all">
<xs:sequence>
<xs:element name="item" type="xs:string" minOccurs="0" maxOccurs="unbounded" nillable="true"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="stringArrayArray" final="#all">
<xs:sequence>
<xs:element name="item" type="tns:stringArray" minOccurs="0" maxOccurs="unbounded" nillable="true"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Можно заметить, что для примера используется WSDL RPC style. Аналогичные действия по валидации предусмотрены для WSDL DOC style.
Добавьте профиль wsdl_rpc в реестр профилей:
sowa-config --add-profile wsdl_rpc
В каталоге proxies создайте конфигурационный файл wsdl_rpc.yml и наполните его следующим содержимым:
version: 2.0.3
profile: wsdl_rpc
profile_version: XXX
system:
wrk_count: 4
conn_count: 4096
optional:
log_level: debug
service:
service_http_proxy:
- id: service
listen:
- port: 8011
name: service
hostname:
- localhost
url: ^\/service$
allowed_queries:
- method: post
upstream_group_id: upstream_v1
upstream_groups:
- id: upstream_v1
servers:
- server: 127.0.0.1:18011
weight: 5
validators:
validator_xsd:
request:
- schema: schemes/xsd/dataset.wsdl
url: ^\/service$
method: post
wsdl: true
response:
- schema: schemes/xsd/dataset.wsdl
url: ^\/service$
method: post
wsdl: true
response_code:
operator: "!~"
pattern: "(?:500|502|503|504)"
За валидацию отвечает секция валидаторов — validators, в которой определяется тип валидатора — validator_xsd.
Внутри данных секций задаются правила валидации, которые для запросов состоят из следующих параметров:
sсhema — файл со схемой валидации. В нашем случае это dataset.wsdl, который импортирует в себе две xsd схемы - dataset.xsd и stringArray.xsd;
method — наименование http-метода для запросов, по которому будет применяться данная схема;
url — параметр, позволяющий соотнести схему валидации xml-объекта и адрес, по которому был отправлен запрос. Значение параметра может быть представлено в виде регулярного выражения. Для явного использования в url символов { } [ ] \ . необходимо их экранирование;
wsdl — в значении параметра указывается флаг, отвечающий за генерацию xsd-схемы на основе указанной в schema. Схемы генерируются в каталог, в котором располагаются скопированные схемы (/sowa/profile_storage/custom/wsdl_rpc/schemes/xsd).
Для ответов дополнительно задали условия на ожидаемый статус ответа (группа параметров response_code), в этом случае будет осуществляться валидация ответов только для данных статусов.
В сервисы заглушек добавим заглушку, которая будет возвращать xml ответ (относительно proxies: …/stubs/services/plain_service.yml).
- id: stub_wsdl_rpc
optional:
response_body: '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dat="http://example.example.com/dataset">
<soapenv:Header/>
<soapenv:Body>
<dat:fetch>
<sessionKey>3</sessionKey>
<providerName>sowa hi</providerName>
<paramNames>
<item>sowasow sowasow</item>
</paramNames>
<paramValues>
<item>sowa sowas sowaso</item>
</paramValues>
<fieldNames>
<item>sowasowaso sow sowas</item>
</fieldNames>
<indexFieldNames>
<item>sow asowa</item>
</indexFieldNames>
<indexFieldValues>
<item>sowaso sowasowa</item>
</indexFieldValues>
<headFields>
<item>sowasowa so</item>
</headFields>
<rowsCount>10</rowsCount>
<version>10</version>
</dat:fetch>
</soapenv:Body>
</soapenv:Envelope>'
response_code: 200
response_headers:
- name: Content-Type
value: text/html
- name: Content-Encoding
value: UTF-8
listen:
- port: 18011
url: ^\/service$
Создайте в ресурсном каталоге профиля wsdl_rpc каталоги schemes и xsd:
mkdir -p /sowa/profile_storage/custom/wsdl_rpc/schemes/xsd
Флаг -p будет создавать вложенные каталоги, но только в случае, если они еще не существуют.
Скопируйте файлы схем в каталог xsd профиля wsdl_rpc:
cp dataset.wsdl /sowa/profile_storage/custom/wsdl_rpc/schemes/xsd
cp dataset.xsd /sowa/profile_storage/custom/wsdl_rpc/schemes/xsd
cp stringArray.xsd /sowa/profile_storage/custom/wsdl_rpc/schemes/xsd
Остановите профиль sample_stub:
sowa-config --stop sample_stub
Переконфигурируйте профиль sample_stub (из каталога proxies):
sowa-config --config ../stubs/sample_stub.yml
Запустите профиль sample_stub:
sowa-config --run sample_stub
Сконфигурируйте профиль wsdl_rpc:
sowa-config --config wsdl_rpc.yml
Запустите профиль wsdl_rpc:
sowa-config --run wsdl_rpc
Создайте файл envelope.xml со следующим содержимым для того, чтобы использовать его в качестве тела запроса:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dat="http://example.example.com/dataset">
<soapenv:Header/>
<soapenv:Body>
<dat:getDataVersions>
<sessionKey>3</sessionKey>
<paramNames>
<item>sowa so</item>
</paramNames>
</dat:getDataVersions>
</soapenv:Body>
</soapenv:Envelope>
Отправьте POST запрос c файлом envelope.xml на сервис service, объявленному в конфигурационном файле профиля wsdl_rpc:
curl -v -d @envelope.xml http://127.0.0.1:8011/service
В результате выполнения команды получили в ответ статус код 200. Это означает, что request/response body успешно провалидировались по схеме.
Валидация по XSD#
Для демонстрации работоспособности валидации по XSD будет использована следующую схему: schema.xsd
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Company">
<xs:complexType>
<xs:sequence>
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="FirstName"/>
<xs:element type="xs:string" name="LastName"/>
<xs:element type="xs:int" name="ContactNo"/>
<xs:element type="xs:string" name="Email"/>
<xs:element name="Address">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="City"/>
<xs:element type="xs:string" name="State"/>
<xs:element type="xs:int" name="Zip"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Добавьте профиль xsd_validation в реестр профилей:
sowa-config --add-profile xsd_validation
В каталоге proxies создайте конфигурационный файл xsd_validation.yml и наполните его следующим содержимым:
version: 2.0.3
profile: xsd_validation
profile_version: XXX
system:
wrk_count: 4
conn_count: 4096
optional:
log_level: debug
service:
service_http_proxy:
- id: service
listen:
- port: 8012
name: service
hostname:
- localhost
url: ^\/service$
allowed_queries:
- method: post
upstream_group_id: upstream_v1
upstream_groups:
- id: upstream_v1
servers:
- server: 127.0.0.1:18012
weight: 5
validators:
validator_xsd:
request:
- schema: schemes/xsd/schema.xsd
wsdl: false
response:
- schema: schemes/xsd/schema.xsd
wsdl: false
За валидацию отвечает секция валидаторов — validators, в которой определяется тип валидатора — validator_xsd.
schema — обязательный параметр секций request/response валидатора — файл со схемой валидации.
параметр wsdl не является обязательным, но мы оставили его для того, чтобы продемонстрировать, что нет необходимости в генерации xsd-схемы на основе wsdl.
В сервисы заглушек добавим заглушку, которая будет возвращать xml ответ (относительно proxies: …/stubs/services/plain_service.yml).
- id: stub_xsd_validation
optional:
response_body: '<?xml version="1.0" encoding="utf-8"?>
<Company>
<Employee>
<FirstName>str1234</FirstName>
<LastName>str1234</LastName>
<ContactNo>123</ContactNo>
<Email>str1234</Email>
<Address>
<City>str1234</City>
<State>str1234</State>
<Zip>123</Zip>
</Address>
</Employee>
</Company>'
response_code: 200
response_headers:
- name: Content-Type
value: text/html
- name: Content-Encoding
value: UTF-8
listen:
- port: 18012
url: ^\/service$
Создайте в ресурсной папке профиля xsd_validation каталоги schemes и xsd:
mkdir -p /sowa/profile_storage/custom/xsd_validation/schemes/xsd
Флаг -p будет создавать вложенные каталоги, но только в случае, если они еще не существуют.
Скопируйте schema.xsd в каталог xsd профиля xsd_validation:
cp schema.xsd /sowa/profile_storage/custom/xsd_validation/schemes/xsd
Сконфигурируйте профиль xsd_validation:
sowa-config -c xsd_validation.yml
Запустите профиль xsd_validation:
sowa-config -r xsd_validation
Переконфигурируйте профиль sample_stub (путь до sample_stub.yml приведен из каталога proxies). Возможен случай, когда профиль не был остановлен ранее. В таком случае конфигуратор выдаст сообщение «Profile sample_stub is running. Are you sure that you want to reconfigure? [y/n]». Нажмите «y».
sowa-config --config ../stubs/sample_stub.yml
Перезапустите профиль sample_stub:
sowa-config --restart sample_stub
Создайте файл envelope2.xml со следующим содержимым для того, чтобы использовать его в качестве тела запроса:
<?xml version="1.0" encoding="utf-8"?>
<Company>
<Employee>
<FirstName>str1234</FirstName>
<LastName>str1234</LastName>
<ContactNo>123</ContactNo>
<Email>str1234</Email>
<Address>
<City>str1234</City>
<State>str1234</State>
<Zip>123</Zip>
</Address>
</Employee>
</Company>
Отправьте POST запрос с файлом envelope2.xml на сервис service, объявленному в конфигурационном файле профиля xsd_validation:
curl -v -d @envelope2.xml http://127.0.0.1:8012/service
В результате выполнения команды был получен в ответ статус код 200. Валидация request/response тела прошла успешно.
Видоизменим файл envelope2.xml, добавив к элементу ContactNo лишние символы — BAD:
<?xml version="1.0" encoding="utf-8"?>
<Company>
<Employee>
<FirstName>str1234</FirstName>
<LastName>str1234</LastName>
<ContactNoBAD>123</ContactNo>
<Email>str1234</Email>
<Address>
<City>str1234</City>
<State>str1234</State>
<Zip>123</Zip>
</Address>
</Employee>
</Company>
Повторите POST запрос с файлом envelope2.xml на сервис service, объявленному в конфигурационном файле профиля xsd_validation:
curl -v -d @envelope2.xml http://127.0.0.1:8012/service
В ответе, от профиля xsd_validation, получили статус код 403 Forbidden, что является ошибкой. Для анализа ошибки перейдите в файлы логов профиля xsd_validation. По умолчанию файлы логов хранятся в «/sowalogs/<profile_name>/». В нашем случае «/sowalogs/xsd_validation/».
Нужен каталог services и его подкаталог service_http_proxy. В нем можем найти для каждого объявленного сервиса access и error журналы (
Посмотрите на «первый» [error], в котором видно, что не удалось найти элемент ContactNoB. Это ошибка валидации связанная с некорректным названием элемента.
Посмотрите вновь к envelope2.xml. Видоизмените его следующим образом — элемент ContactNo имеет тип int. Изменим содержимое данного поля, добавив к числу строку.
<?xml version="1.0" encoding="utf-8"?>
<Company>
<Employee>
<FirstName>str1234</FirstName>
<LastName>str1234</LastName>
<ContactNo>123BAD</ContactNo>
<Email>str1234</Email>
<Address>
<City>str1234</City>
<State>str1234</State>
<Zip>123</Zip>
</Address>
</Employee>
</Company>
Повторите POST запрос с файлом envelope2.xml на сервис service, объявленному в конфигурационном файле профиля xsd_validation:
curl -v -d @envelope2.xml http://127.0.0.1:8012/service
В ответе от профиля xsd_validation, была получена ошибка со статус кодом 403 Forbidden. Перейдите к журналу error, чтобы проанализировать ее.

Здесь видно, что ошибка валидации связана с ограничением схемы на передаваемый тип данных.
Настройка валидации подробно описана в разделе «Валидация по wsdl/xsd схеме».